Почти неделю вникал в новшества Андроида. Большие затруднения вызвала версия API 21. Перекопал много источников, но не один из них не подходил на 100%. Очень часто возникали ошибки компиляции или программа умирала на моменте запуска. Буквально на днях наткнулся на статью, где по шагам описаны все действия и приложены исходники. Но с ней тоже пришлось повозится, поскольку программа умирала при запуске. Еще странность была в том, что, хоть я и создал проект с нуля всего с одной главной Activity, компилятор периодически сообщал мне, что не может найти главный класс приложения и, естественно, отказывался работать.
Итак, мы будем делать модный дизайн с выезжающим меню и плавающей кнопкой. Сразу признаюсь, что эта статья является вольной интерпретацией источника с небольшими дополнениями.
2. Открываем res -> values -> strings.xml и добавляем строки:
3. Открываем (если такого файла нет, тогда просто создайте его) res -> values -> colors.xml и добавляем следующее
4. Открываем файл res -> values -> dimens.xml и создаем измеритель
5. Открываем res -> values -> styles.xml и создаем в нем свою тему для приложения
Вот тут есть тонкий момент. При попытке запустить приложение (конечно, когда все будет сделано), оно умирало. Все дело было в строке
Ее стоит убрать из темы, если такое происходит. Как я понял, все дело в AppCompat. Для новых версий этот параметр не нужен, он регулируется родительской темой. Соответственно, что бы не получить в последствии два тулбара, нужно изменить родительскую тему с Theme.AppCompat.Light.DarkActionBar на Theme.AppCompat.Light.NoActionBar. В этом случае тулбара по умолчанию не будет и приложение запустится.
6. Теперь внесем корректуры для Android Lollipop (API 21). Для этого создадим файл styles.xml в папке res -> vales. Да, такой файл уже есть, но при создании файла в Android Studio в качестве дополнительного параметра можно указать версию. Ставим туда 21, В этом случае Android Studio создаст папку values-v21 и поместит туда файл styles.xml. В самой Android Studio папка не появится, но появится возможность раскрыть файл styles.xml.
В файл srtles.xml для Android Lollipop (API 21) добавляем следующие строки:
7. Теперь у нас есть готовая тема. Для того, что бы ее применить, нужно указать ее в файле манифеста (AndroidManifest.xml), а именно, в теге <application> изменить атрибут
Итого:
9. Открываем main_activity.xml и добавляем в него тулбар, используя тег <include>
Можно запускать приложение, все должно работать. Должно появится пустое приложение с тулбаром и в цветах нашей темы.
11. Для того, что бы импортировать иконку, нажмите правой кнопкой мыши res -> New -> Image Asset. Укажите тип Action Bar and Tab Icons и укажите имя ресурса ic_action_search.
12. Открываем res -> menu -> menu_main.xml и добавляем еще один пункт
13. Далее, меняем MainActivity.java. По умолчанию, Android Studio создает класс Activity, унаследованный от ActionBarActivity. Но теперь этот класс запрещен к использованию. Дело опять в AppCompat. Теперь Activity нужно унаследовать от класса AppCompatActivity, в котором все есть от ActionBarActivity, а сам Action Bar регулируется темой приложения.
14. Немного реорганизуем код. Создадим в нашем пакете еще 3 пакета: activity, adapter и model. Переместим MainActivity.java в пакет activity
15. Откроем файл build.gradle для app и добавим зависимость. После этого выполним Build -> Rebuild Project, что бы пересобрать проект.
18. Скачаем иконку профиля и импортируем в проект. Как это сделать было описано ранее.
19. Создадим файл res -> layout -> fragment_navigation_drawer.xml, в котором будет полное описание представления навигации
20. Теперь нужно создать адаптер для RecyclerView. В пакете adapter создаем класс NavigationDrawerAdapter.java
23. Теперь внесем изменения в MainActivity.java.
Почти все готово
По такому же подобию создайте еще 2 файла fragment_friends.xml и fragment_messages.xml
25. В пакете activity создадим класс HomeFragment.java
По этому же подобию создайте еще 2 класса FriendsFragment.java и MessagesFragment.java
26. Добавим несколько изменений в MainActivity.java, что бы была возможность обрабатывать пункты меню
Если Вы все сделали верно и в мире ничего не произошло, то Ваше приложение запустится и будет Вам счастье!
Итак, мы будем делать модный дизайн с выезжающим меню и плавающей кнопкой. Сразу признаюсь, что эта статья является вольной интерпретацией источника с небольшими дополнениями.
Создание Material Design темы
1. Создаем новый проект File -> New Project. Заполняем все необходимые поля. Когда появится вопрос о создании Activity, выберите Blank Activity.2. Открываем res -> values -> strings.xml и добавляем строки:
3. Открываем (если такого файла нет, тогда просто создайте его) res -> values -> colors.xml и добавляем следующее
4. Открываем файл res -> values -> dimens.xml и создаем измеритель
5. Открываем res -> values -> styles.xml и создаем в нем свою тему для приложения
Вот тут есть тонкий момент. При попытке запустить приложение (конечно, когда все будет сделано), оно умирало. Все дело было в строке
Ее стоит убрать из темы, если такое происходит. Как я понял, все дело в AppCompat. Для новых версий этот параметр не нужен, он регулируется родительской темой. Соответственно, что бы не получить в последствии два тулбара, нужно изменить родительскую тему с Theme.AppCompat.Light.DarkActionBar на Theme.AppCompat.Light.NoActionBar. В этом случае тулбара по умолчанию не будет и приложение запустится.
6. Теперь внесем корректуры для Android Lollipop (API 21). Для этого создадим файл styles.xml в папке res -> vales. Да, такой файл уже есть, но при создании файла в Android Studio в качестве дополнительного параметра можно указать версию. Ставим туда 21, В этом случае Android Studio создаст папку values-v21 и поместит туда файл styles.xml. В самой Android Studio папка не появится, но появится возможность раскрыть файл styles.xml.
В файл srtles.xml для Android Lollipop (API 21) добавляем следующие строки:
7. Теперь у нас есть готовая тема. Для того, что бы ее применить, нужно указать ее в файле манифеста (AndroidManifest.xml), а именно, в теге <application> изменить атрибут
Итого:
Добавляем Toolbar (ActionBar)
8. Создаем файл res -> layout -> toolbar.xml9. Открываем main_activity.xml и добавляем в него тулбар, используя тег <include>
Можно запускать приложение, все должно работать. Должно появится пустое приложение с тулбаром и в цветах нашей темы.
Теперь давайте добавим кнопку в тулбар.
10. Скачайте иконку и импортируйте ее в Android Studio как Image Asset11. Для того, что бы импортировать иконку, нажмите правой кнопкой мыши res -> New -> Image Asset. Укажите тип Action Bar and Tab Icons и укажите имя ресурса ic_action_search.
12. Открываем res -> menu -> menu_main.xml и добавляем еще один пункт
13. Далее, меняем MainActivity.java. По умолчанию, Android Studio создает класс Activity, унаследованный от ActionBarActivity. Но теперь этот класс запрещен к использованию. Дело опять в AppCompat. Теперь Activity нужно унаследовать от класса AppCompatActivity, в котором все есть от ActionBarActivity, а сам Action Bar регулируется темой приложения.
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends ActionBarActivity {
private Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Добавляем левое меню (Navigation Drawer)
Для создания меню мы используем RecyclerView, вместо обычного ListView, как это было в ранних версиях.14. Немного реорганизуем код. Создадим в нашем пакете еще 3 пакета: activity, adapter и model. Переместим MainActivity.java в пакет activity
15. Откроем файл build.gradle для app и добавим зависимость. После этого выполним Build -> Rebuild Project, что бы пересобрать проект.
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.0.0'
compile 'com.android.support:recyclerview-v7:21.0.+'
}
16. В пакете model создадим класс NawDrawerItem.java. Этот класс будет описывать каждую строку нашей навигацииpackage androidhive.info.materialdesign.model;
public class NavDrawerItem {
private boolean showNotify;
private String title;
public NavDrawerItem() {
}
public NavDrawerItem(boolean showNotify, String title) {
this.showNotify = showNotify;
this.title = title;
}
public boolean isShowNotify() {
return showNotify;
}
public void setShowNotify(boolean showNotify) {
this.showNotify = showNotify;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
17. В res -> layout создадим файл nav_drawer_row.xml, который будет описывать представление каждой строки навигации.18. Скачаем иконку профиля и импортируем в проект. Как это сделать было описано ранее.
19. Создадим файл res -> layout -> fragment_navigation_drawer.xml, в котором будет полное описание представления навигации
20. Теперь нужно создать адаптер для RecyclerView. В пакете adapter создаем класс NavigationDrawerAdapter.java
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.Collections;
import java.util.List;
/**
* Created by Ravi Tamada on 12-03-2015.
*/
public class NavigationDrawerAdapter extends RecyclerView.Adapter {
List data = Collections.emptyList();
private LayoutInflater inflater;
private Context context;
public NavigationDrawerAdapter(Context context, List data) {
this.context = context;
inflater = LayoutInflater.from(context);
this.data = data;
}
public void delete(int position) {
data.remove(position);
notifyItemRemoved(position);
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.nav_drawer_row, parent, false);
MyViewHolder holder = new MyViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
NavDrawerItem current = data.get(position);
holder.title.setText(current.getTitle());
}
@Override
public int getItemCount() {
return data.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView title;
public MyViewHolder(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
}
}
}
21. В пакете activity создадим фрагмент FragmentDrawer.javaimport android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class FragmentDrawer extends Fragment {
private static String TAG = FragmentDrawer.class.getSimpleName();
private RecyclerView recyclerView;
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private NavigationDrawerAdapter adapter;
private View containerView;
private static String[] titles = null;
private FragmentDrawerListener drawerListener;
public FragmentDrawer() {
}
public void setDrawerListener(FragmentDrawerListener listener) {
this.drawerListener = listener;
}
public static List getData() {
List data = new ArrayList<>();
// preparing navigation drawer items
for (int i = 0; i < titles.length; i++) {
NavDrawerItem navItem = new NavDrawerItem();
navItem.setTitle(titles[i]);
data.add(navItem);
}
return data;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// drawer labels
titles = getActivity().getResources().getStringArray(R.array.nav_drawer_labels);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflating view layout
View layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
recyclerView = (RecyclerView) layout.findViewById(R.id.drawerList);
adapter = new NavigationDrawerAdapter(getActivity(), getData());
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new ClickListener() {
@Override
public void onClick(View view, int position) {
drawerListener.onDrawerItemSelected(view, position);
mDrawerLayout.closeDrawer(containerView);
}
@Override
public void onLongClick(View view, int position) {
}
}));
return layout;
}
public void setUp(int fragmentId, DrawerLayout drawerLayout, final Toolbar toolbar) {
containerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActivity().invalidateOptionsMenu();
}
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
getActivity().invalidateOptionsMenu();
}
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
toolbar.setAlpha(1 - slideOffset / 2);
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
});
}
public static interface ClickListener {
public void onClick(View view, int position);
public void onLongClick(View view, int position);
}
static class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
private GestureDetector gestureDetector;
private ClickListener clickListener;
public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
this.clickListener = clickListener;
gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null) {
clickListener.onLongClick(child, recyclerView.getChildPosition(child));
}
}
});
}
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
clickListener.onClick(child, rv.getChildPosition(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
}
public interface FragmentDrawerListener {
public void onDrawerItemSelected(View view, int position);
}
}
22. Теперь открываем main_activity.xml и изменяем его, как показано в коде ниже23. Теперь внесем изменения в MainActivity.java.
Почти все готово
Добавляем обработку пунктов навигации
24. Создадим файл res -> layout -> fragment_home.xmlПо такому же подобию создайте еще 2 файла fragment_friends.xml и fragment_messages.xml
25. В пакете activity создадим класс HomeFragment.java
По этому же подобию создайте еще 2 класса FriendsFragment.java и MessagesFragment.java
26. Добавим несколько изменений в MainActivity.java, что бы была возможность обрабатывать пункты меню
Если Вы все сделали верно и в мире ничего не произошло, то Ваше приложение запустится и будет Вам счастье!
Комментарии
Отправить комментарий