Боковое меню в Android
начал изучать android разработку недавно. Писал небольшое приложение на android и в нем нужно сделать боковое меню . Я пробовал сделать с шаблоном из Android Studio, Navigation Drawer Activity, но раз я обращаюсь к вам, понятно, что у меня ничего не получилось. Я много гуглил свой вопрос, но нигде не нахожу подходящего туториала(единственное исключение, наверное является эта шикарная статья с Хабра, но вот зараза, здесь написано на Kotlin, а мне нужно на Java), пожалуйста расскажите ПОШАГОВО, как создать боковое меню в Android Studio?
Отслеживать
26.7k 7 7 золотых знаков 32 32 серебряных знака 49 49 бронзовых знаков
задан 30 окт 2019 в 13:13
midnightelf18 midnightelf18
1,879 14 14 серебряных знаков 29 29 бронзовых знаков
2 ответа 2
Сортировка: Сброс на вариант по умолчанию
Вот инструкция как добавить в приложение нужный вам макет. Будем рассматривать ситуацию, когда вы будете создавать новое приложение, учитывая приведенную информацию в вопросе. При создании нового проекта вы можете выбрать Drawer activity как вы уже пробовали и дальше студия все сделает за вас. Будут созданы все необходимые классы для поддержки, разметка (которую можно будет кастомизировать по вашему усмотрению), ресурсы для меню и тому подобное. Разобраться что для чего в таком варианте совсем несложно. Есть второй вариант — создавать приложение на основе пустой активности (Empty activity) и дальше все делать вручную. Для начала нужно создать проект и перейти в файл разметки activity_main.xml и добавить соответствующий код:
Дальше вам нужно добавить пункты меню которые будут отображаться, для этого переходим в файл строковых ресурсов и добавляем массив со своими данными:
- Screen 1
- Screen 2
- Screen 3
Следующим шагом будет создание разметки пункта меню, поэтому создаем файл drawer_list_item.xml :
После создания разметки пункта меню, нужно подумать над тем как будет отображаться нажатия и отмечание выбранного пункта меню, поэтому создаем в папке drawable файл activated_background.xml :
и в ресурсах цвета добавляем нужный цвет:
- #FF33B5E5
После того как с оформлением закончено нужно подумать над логикой поведения нашего меню, вот активность:
public class MainActivity extends ActionBarActivity < private String[] mScreenTitles; private DrawerLayout mDrawerLayout; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; private CharSequence mDrawerTitle; private CharSequence mTitle; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTitle = mDrawerTitle = getTitle(); mScreenTitles = getResources().getStringArray(R.array.screen_array); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.left_drawer); // Set the adapter for the list view mDrawerList.setAdapter(new ArrayAdapter(this, R.layout.drawer_list_item, mScreenTitles)); // Set the list's click listener mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setHomeButtonEnabled(true); mDrawerToggle = new ActionBarDrawerToggle( this, /* host Activity */ mDrawerLayout, /* DrawerLayout object */ R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */ R.string.drawer_open, /* "open drawer" description */ R.string.drawer_close /* "close drawer" description */ ) < /** Called when a drawer has settled in a completely closed state. */ public void onDrawerClosed(View view) < getSupportActionBar().setTitle(mTitle); supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() >/** Called when a drawer has settled in a completely open state. */ public void onDrawerOpened(View drawerView) < getSupportActionBar().setTitle(mDrawerTitle); supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() >>; // Set the drawer toggle as the DrawerListener mDrawerLayout.setDrawerListener(mDrawerToggle); // Initialize the first fragment when the application first loads. if (savedInstanceState == null) < selectItem(0); >> @Override public boolean onCreateOptionsMenu(Menu menu) < // Inflate the menu; MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); >/* Called whenever we call invalidateOptionsMenu() */ @Override public boolean onPrepareOptionsMenu(Menu menu) < // If the nav drawer is open, hide action items related to the content view boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); menu.findItem(R.id.action_search).setVisible(!drawerOpen); return super.onPrepareOptionsMenu(menu); >@Override public boolean onOptionsItemSelected(MenuItem item) < // Pass the event to ActionBarDrawerToggle, if it returns // true, then it has handled the app icon touch event if (mDrawerToggle.onOptionsItemSelected(item)) < return true; >// Handle action buttons switch(item.getItemId()) < case R.id.action_search: // Show toast about click. Toast.makeText(this, R.string.action_search, Toast.LENGTH_SHORT).show(); return true; default: return super.onOptionsItemSelected(item); >> /* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener < @Override public void onItemClick(AdapterViewparent, View view, int position, long id) < selectItem(position); >> /** Swaps fragments in the main content view */ private void selectItem(int position) < // Update the main content by replacing fragments Fragment fragment = null; switch (position) < case 0: fragment = new ScreenOne(); break; case 1: fragment = new ScreenTwo(); break; case 2: fragment = new ScreenThree(); break; default: break; >// Insert the fragment by replacing any existing fragment if (fragment != null) < FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.content_frame, fragment).commit(); // Highlight the selected item, update the title, and close the drawer mDrawerList.setItemChecked(position, true); setTitle(mScreenTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); >else < // Error Log.e(this.getClass().getName(), "Error. Fragment is not created"); >> @Override public void setTitle(CharSequence title) < mTitle = title; getSupportActionBar().setTitle(mTitle); >/** * When using the ActionBarDrawerToggle, you must call it during * onPostCreate() and onConfigurationChanged(). */ @Override protected void onPostCreate(Bundle savedInstanceState) < super.onPostCreate(savedInstanceState); // Sync the toggle state after onRestoreInstanceState has occurred. mDrawerToggle.syncState(); >@Override public void onConfigurationChanged(Configuration newConfig) < super.onConfigurationChanged(newConfig); // Pass any configuration change to the drawer toggles mDrawerToggle.onConfigurationChanged(newConfig); >>
ну и для корректной работы вам нужно создать необходимое кол-во фрагментов, которые будут показывать пользователю какие-то данные:
public class ScreenOne extends Fragment < public ScreenOne() < >@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < View rootView = inflater.inflate(R.layout.screen_first, container, false); return rootView; >>
на каждом фрагменте можно сделать свою разметку. Вот туториал.
Реализация выдвижного меню NavigationDrawer при помощи DrawerLayout, с использованием произвольной разметки
На днях для одного из разрабатываемого нашей командой приложения, заказчик внес правку в дизайн, которая требовала разработать выдвижное меню с довольно не стандартным расположением view компонентов. Хотя на данный момент и существуют различные виды реализации данной задачи, они оказывались либо слишком объемными, либо не предоставляли реализацию нужного функционала.
Обдумав некоторое время данную задачу, я решил реализовать данное меню на основе стандартного компонента DrawerLayout, в основу которого было вложено 2 root элемента — RelativeLayout для основной разметки окна, а также еще один RelativeLayout как контейнер для бокового меню. Хотелось бы добавить, что именно 2 root элемента должно быть внутри DrawerLayout, подробнее об этом контейнере можно прочесть в официальной документации гугла.
Реализация
Xml файл разметки для основной activity
android:clickable="true" android:background="#FFFFFF" xmlns:android="http://schemas.android.com/apk/res/android" />
Разметка основной activity готова, теперь приступим к написанию класса, который будет выполнять основную логику. Создадим класс, наследующий RelativeLayout. Данный класс реализует всю логику нашего меню, в том числе устанавливает разметку и определяет все view.
public class NavigationLayout extends RelativeLayout < Button ok; public NavigationLayout(Context context,RelativeLayout parent) < super(context); initView(context,parent); >public void initView(final Context context,RelativeLayout parent) < // надуваем любой xml файл разметки View view= LayoutInflater.from(context).inflate(R.layout.view_drawer_layout,parent,true); ok=(Button)view.findViewById(R.id.ok); ok.setOnClickListener(new OnClickListener() < @Override public void onClick(View v) < Toast.makeText(context,"Ok",Toast.LENGTH_SHORT).show(); >>); > >
В конструктор следует передать context и parent.
parent — RelativeLayout, который был объявлен в разметке для основной activity ( )
Далее функция initView(final Context context,RelativeLayout parent) — надувает основную разметку, которая будет помещена в выдвижное меню, а также определим тут все view компоненты и их слушатели.
В R.layout.view_drawer_layout для примера я объявил всего одну кнопку.
На данном этапе основная часть готова, осталось лишь добавить наш NavigationLayout при помощи addView к основному parent контейнеру.
Создадим класс, наследующий AppCompactActivity
public class ParentNavigationActivity extends AppCompatActivity < NavigationLayout navigationLayout; RelativeLayout left_drawer; @Override public void setContentView(@LayoutRes int layoutResID) < super.setContentView(layoutResID); setupMenu(); >public void setupMenu() < left_drawer=(RelativeLayout) findViewById(R.id.left_drawer); navigationLayout=new NavigationLayout(getApplicationContext(),left_drawer); left_drawer.addView(navigationLayout); >>
Данный класс переопределяет стандартный метод setContentView, добавляя в него вызов функции, которая ‘инициализирует’ выдвижное меню. Также здесь мы создаем объект ранее написанного нами NavigationLayout класса и добавляем его при помощи left_drawer.addView(navigationLayout) к родителю, который и является контейнером бокового меню.
Осталось дело за малым — чтобы все заработало, нужно лишь создать экран (activity) и унаследовать ParentNavigationActivity, который мы только что создали.
public class MainActivity extends ParentNavigationActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_test); >>
Таким образом, при наследовании ParentNavigationActivity и вызове функции setContentView, в нашей activity появляется готовое меню.
Хотелось бы добавить, что 2 контейнера, лежащих в основе DrawerLayout, необязательно должны быть RelativeLayout. Вместо них можно использовать constraintlayout, framelayout, linearlayout и другие.
На данном этапе разработка выдвижного меню завершена!
Данный способ является довольно простым в реализации, а также гибким в плане добавления меню к любым activity. Надеюсь что данная статья поможет android разработчикам упростить создание бокового меню для своих приложений.
- Android application development
- navigation Drawer
- drawer Layout
- drawer Layout with custom xml
- боковое меню
- выдвижное меню
- меню c произвольной разметкой xml.
- Разработка мобильных приложений
- Разработка под Android
Реализуем боковую навигацию в Android
В последнее время среди паттернов проектирования мобильных приложений наблюдается устойчивая тенденция к упрощению взаимодействия пользователя с конечным приложением. В частности, особый упор начал делаться на распознавание жестов. Жесты интуитивно понятны и естественны, они удобны и позволяют избавиться от лишних элементов интерфейса, упрощая приложение.
Хороший пример правильного использования жестов — набирающая популярность боковая навигация. На Хабре ранее публиковалась статья о боковой навигации как паттерне, но в ней ничего не было сказано о реализации.
К сожалению, проектов, реализующих боковую навигацию, крайне мало, да и большая часть из них работает медленно и неудобно. Мне повезло: спустя некоторое время после начала поиска я наткнулся на проект ActionsContentView, который, на мой взгляд, работал хорошо и быстро. В проекте были решены все те проблемы, с которым я столкнулся когда-то сам. После внимательного изучения проекта он был немного переписан мною под собственные нужды.
Изначально я хотел в этой статье расписать как и способ открытия бокового меню по клику, так и способ открытия меню жестом. Однако ближе к концу статьи стало очевидно, что обработка жестов и открытие навигации по ним достаточно объемный вопрос, в котором также следует учесть множество особенностей. Статья в таком случаем получается настолько огромная, что читать ее просто неудобно.
Поэтому я решил описать пока лишь реализацию бокового меню по клику.
Архитектура приложения
В качестве слоя с контентом мы будем использовать Fragment, меню же у нас будет располагаться в Activity на заднем плане.
Преимущество фрагментов очевидно: фактически, мы сможем использовать внутри них все преимущества Activity, плюс из Activity слой с фрагментом видится как View, что позволит нам использовать стандартные и привычные методы работы с ним как со слоем.
Activity мы сделаем статичным, при переходах внутри фрагмента у нас должен меняться только сам фрагмент. Также необходимо предусмотреть во фрагменте метод старта нового фрагмента в этом же окне, а также методы открытия/закрытия меню.
Для реализации этого создадим интерфейс, описывающий методы взаимодействия фрагмента и Activity:
import android.support.v4.app.Fragment; public interface SideMenuListener
Реализуем его в Activity:
import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity implements SideMenuListener < @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); >public void startFragment(Fragment fragment) < // TODO Auto-generated method stub >public boolean toggleMenu() < // TODO Auto-generated method stub return false; >>
Так как нам необходимо иметь доступ вышеперечисленным методам из любого фрагмента с контентом, расширим класс Fragment и добавим их:
import android.support.v4.app.Fragment; public class ContentFragment extends Fragment < protected void startFragment(Fragment fragment) < ((SideMenuListener) getActivity()).startFragment(fragment); >protected boolean toggleMenu() < return ((SideMenuListener) getActivity()).toggleMenu(); >>
В дальнейшем все наши фрагменты мы будем наследовать от него.
Создаем разметку, реализуем смену фрагментов
Теперь нам потребуется создать список, имитирующий само меню, и заполнить его. Также нам потребуется сам фрагмент с контентом.
Файл разметки Activity невероятно прост:
Так же, как и его заполнение:
private String[] names = < "Иван", "Марья", "Петр", "Антон", "Даша", "Борис", "Костя", "Игорь", "Анна", "Денис", "Андрей", "Иван", "Марья", "Петр", "Антон", "Даша" >; @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView menu = (ListView) findViewById(R.id.menu); ArrayAdapteradapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, names); menu.setAdapter(adapter); >
Создадим и добавим теперь наш фрагмент:
import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; public class TestFragment extends ContentFragment < public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < View v = inflater.inflate(R.layout.test_fragment, container, true); Button toogle = (Button) v.findViewById(R.id.toggle); toogle.setOnClickListener( new OnClickListener() < public void onClick(View arg0) < toggleMenu(); >>); return v; > >
По этой кнопке, как вы уже догадались, мы будем открывать или закрывать меню.
Реализуем пока механизм смены фрагментов:
public class MainActivity extends FragmentActivity implements SideMenuListener < private String[] names = < "Иван", "Марья", "Петр", "Антон", "Даша", "Борис", "Костя", "Игорь", "Анна", "Денис", "Андрей", "Иван", "Марья", "Петр", "Антон", "Даша" >; private FragmentTransaction fragmentTransaction; private View content; private int contentID = R.id.content; @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); content = findViewById(contentID); // . >public void startFragment(Fragment fragment) < fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(contentID, fragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); >// . >
Добавим получившийся фрагмент поверх Activity:
Каркас готов, теперь можно реализовывать саму боковую навигацию.
Боковая навигация по клику
Метод toggleMenu() автоматически в зависимости от состояния меню открывает или закрывает его. Соответственно, нам необходимо хранить состояние.
Также нам необходимо иметь значение координаты, до которой меню будет «доезжать» в случае открытия. Так как дисплеи мобильных телефонов имеют разную ширину, хранить необходимо коэффициент, а само значение вычислять исходя из разрешения телефона.
Желательно также указать и продолжительность действия анимации открытия и закрытия в миллисекундах.
public class MainActivity extends FragmentActivity implements SideMenuListener < private final double RIGTH_BOUND_COFF = 0.75; private static int DURATION = 250; private boolean isContentShow = true; private int rightBound; // .. @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); rightBound = (int) (displaymetrics.widthPixels * RIGTH_BOUND_COFF); // .. >>
Теперь немного о реализации класса, который будет прокручивать меню. Для наших целей мы будем использовать класс Scroller, инкапсулирующий прокрутку. Фактически этот класс принимает в себя начальную точку и значение смещения, а затем в течении некоторого времени генерирует некое число.
Чаще всего Scroller используют внутри потока, рекурсивно вызывающего себя. Во всех примерах, которые я встречал, Scroller используется именно так.
Возможно его можно использовать и совместно с бесконечным циклом в отдельном потоке, однако я решил использовать именно такую реализацию.
За открытие/закрытие меню у нас отвечают методы openMenu() и closeMenu(). Этим методы реинициализируют переменные начала скроллинга и запускают метод fling(), занимающийся, собственно, сдвигом.
- Пока анимация присутствует, с помощью View.scrollTo() сдвигает элемент на значение, указываемое Scroller
- Рекурсивно запускает свой поток еще раз, для последующей анимации
Собственно, сам класс, сделан внутренним:
private class ContentScrollController implements Runnable < private final Scroller scroller; private int lastX = 0; public ContentScrollController(Scroller scroller) < this.scroller = scroller; >public void run() < if (scroller.isFinished()) return; final boolean more = scroller.computeScrollOffset(); final int x = scroller.getCurrX(); final int diff = lastX - x; if (diff != 0) < content.scrollBy(diff, 0); lastX = x; >if (more) content.post(this); > public void openMenu(int duration) < isContentShow = false; final int startX = content.getScrollX(); final int dx = rightBound + startX; fling(startX, dx, duration); >public void closeMenu(int duration) < isContentShow = true; final int startX = content.getScrollX(); final int dx = startX; fling(startX, dx, duration); >private void fling(int startX, int dx, int duration) < if (!scroller.isFinished()) scroller.forceFinished(true); if (dx == 0) return; if (duration scroller.startScroll(startX, 0, dx, 0, duration); lastX = startX; content.post(this); > >
Теперь нам осталось лишь инициализировать такое поле в классе и заполнить toggleMenu():
public class MainActivity extends FragmentActivity implements SideMenuListener < private ContentScrollController menuController; // . @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); menuController = new ContentScrollController(new Scroller(getApplicationContext(), new DecelerateInterpolator(3))); // . >public boolean toggleMenu() < if(isContentShow) menuController.openMenu(DURATION); else menuController.closeMenu(DURATION); return isContentShow; >>
Готово. Мы имеем быстрое боковое меню, открывающееся по кнопке. Единственный баг — меню прокручивается во время скроллинга по фрагменту. Для устранения этого бага необходимо проверять, входят ли координаты нажатия пальца в область фрагмента и в зависимости от этого определять, используется ли событие или нет.
public class MainActivity extends FragmentActivity implements SideMenuListener < private Rect contentHitRect = new Rect(); // . @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); content.setOnTouchListener(new OnTouchListener() < public boolean onTouch(View v, MotionEvent event) < v.getHitRect(contentHitRect); contentHitRect.offset(-v.getScrollX(), v.getScrollY()); if (contentHitRect.contains((int)event.getX(), (int)event.getY())) return true; return v.onTouchEvent(event); >>); // . > >
Вот теперь все работает.
Полученное боковое меню очень быстро работает на самых разных телефонах, при этом у нас имеется готовое архитектурное решение организации смены экранов.
Буду рад любым замечаниям.
Готовый исходный код
SideMenuListener.java
package com.habr.sidemenu; import android.support.v4.app.Fragment; public interface SideMenuListener
ContentFragment.java
package com.habr.sidemenu; import android.support.v4.app.Fragment; public class ContentFragment extends Fragment < protected void startFragment(Fragment fragment) < ((SideMenuListener) getActivity()).startFragment(fragment); >protected boolean toggleMenu() < return ((SideMenuListener) getActivity()).toggleMenu(); >>
TestFragment.java
package com.habr.sidemenu; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.Button; public class TestFragment extends ContentFragment < public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < View v = inflater.inflate(R.layout.test_fragment, container, true); Button toogle = (Button) v.findViewById(R.id.toggle); toogle.setOnClickListener( new OnClickListener() < public void onClick(View arg0) < toggleMenu(); >>); return v; > >
MainActivity.java
package com.habr.sidemenu; import android.graphics.Rect; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.animation.DecelerateInterpolator; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.Scroller; public class MainActivity extends FragmentActivity implements SideMenuListener < private String[] names = < "Иван", "Марья", "Петр", "Антон", "Даша", "Борис", "Костя", "Игорь", "Анна", "Денис", "Андрей", "Иван", "Марья", "Петр", "Антон", "Даша" >; private FragmentTransaction fragmentTransaction; private View content; private int contentID = R.id.content; private final double RIGTH_BOUND_COFF = 0.75; private static int DURATION = 250; private boolean isContentShow = true; private int rightBound; private ContentScrollController menuController; private Rect contentHitRect = new Rect(); @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); content = findViewById(contentID); menuController = new ContentScrollController(new Scroller(getApplicationContext(), new DecelerateInterpolator(3))); DisplayMetrics displaymetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displaymetrics); rightBound = (int) (displaymetrics.widthPixels * RIGTH_BOUND_COFF); content.setOnTouchListener(new OnTouchListener() < public boolean onTouch(View v, MotionEvent event) < v.getHitRect(contentHitRect); contentHitRect.offset(-v.getScrollX(), v.getScrollY()); if (contentHitRect.contains((int)event.getX(), (int)event.getY())) return true; return v.onTouchEvent(event); >>); ListView menu = (ListView) findViewById(R.id.menu); ArrayAdapter adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, names); menu.setAdapter(adapter); > public void startFragment(Fragment fragment) < fragmentTransaction = getSupportFragmentManager().beginTransaction(); fragmentTransaction.replace(contentID, fragment); fragmentTransaction.addToBackStack(null); fragmentTransaction.commit(); >public boolean toggleMenu() < if(isContentShow) menuController.openMenu(DURATION); else menuController.closeMenu(DURATION); return isContentShow; >private class ContentScrollController implements Runnable < private final Scroller scroller; private int lastX = 0; public ContentScrollController(Scroller scroller) < this.scroller = scroller; >public void run() < if (scroller.isFinished()) return; final boolean more = scroller.computeScrollOffset(); final int x = scroller.getCurrX(); final int diff = lastX - x; if (diff != 0) < content.scrollBy(diff, 0); lastX = x; >if (more) content.post(this); > public void openMenu(int duration) < isContentShow = false; final int startX = content.getScrollX(); final int dx = rightBound + startX; fling(startX, dx, duration); >public void closeMenu(int duration) < isContentShow = true; final int startX = content.getScrollX(); final int dx = startX; fling(startX, dx, duration); >private void fling(int startX, int dx, int duration) < if (!scroller.isFinished()) scroller.forceFinished(true); if (dx == 0) return; if (duration scroller.startScroll(startX, 0, dx, 0, duration); lastX = startX; content.post(this); > > >
Android Studio: Как сделать боковое меню с помощью NavigationDrawer
В этой статье давайте разберем, как сделать «крутое» боковое меню с помощью компонента NavigationDrawer.
Создадим новый проект, пусть он называется NavDraw, так как использовать на этот раз будем не Empty Activity а Navigation Drawer Activity, шаблон заготовку изAndroid Studio.
После запуска проекта и эмулятора, можно увидеть, как выглядит боковое меню. Справа располагается обычное меню, как сделать которое мы разбирали в прошлых статьях.
Собственно, создание Navigation Drawer меню заключается в изменении существующей заготовки под свои нужды. Этим и займемся сегодня.
Давайте для примера их переведём на русский язык. Для этого давайте определимся, где и что у нас находится в каком файле, какие элементы. Как видите, это многослойный пирог получается, в одном файле хранится часть ресурсов, отвечающих за изображение вверху меню.
Файл nav_header_main.xml
Вот конкретно в этом файле nav_header_main мы сейчас изменим название. Я напишу название на свой лад «NavDraw — боковое меню» в этом textview, в следующим TextView указан адрес android studio, но я напишу название своего сайта.
Картинку я пока менять не буду я не нашел честно говоря, но вы можете в принципе аналогичным образом прописать в папки drawable новую иконку. Они тут расположены в png формате, есть некоторые в xml.
Можно в принципе использовать либо такие, либо такие, но я пока просто покажу вам где она находится если захотите, будете менять уже под свои нужды. Давайте перезапустим наше приложение и посмотрим, что у нас получится.
По идее, данные должны обновиться, так работает большинство приложений, кто собирает на Android Studio.
И в принципе не надо здесь все с нуля как бы переписывать создавать, все уже готово.
Вот кстати, здесь отличие -меню будет работать, которое находится в правом углу, (три точки) без всяких шаманств, изощрений, не как в прошлый раз. В прошлом видео я вам показывал: прописываете кучу стиле и прочего.
Файл activity_main_drawer
Так давайте теперь найдем в папке меню
Вот непосредственно наши пункты, как видите, здесь схалтурили разработчики этого шаблона — они прописали хардкорно пункт android title прямо в теле xml.
А в strings.xml ничего не прописано, но мы не будем сейчас создавать новые пункты в strings.xml
Давайте просто я напишу по-русски так как я вижу, как я понимаю эти пункты, просто и наглядно.
Большинство людей так и делают, если есть пункт, если есть его айдишник — меняем название и дальше можно будет к нему прицепиться и использовать его для обработчика нажатия на этот пункт.
Как видите, перевод произошел, я не готовил специально тоже иконки, пока оставим как есть, хотя если вы создадите новый пункт, вам можно будет подобрать иконку, картинку либо вообще ее удалить.
Удалив просто строку android icon пропадет картинка хотя в принципе лучше конечно что-то подготовить. Давайте продублируем предыдущий пункт, внесем изменения в его ID.
Сделаем пункт по которому приложение будет закрываться, так как бы любимая кнопка начинающего разработчика это Close и Exit — выход и закрыть.
Я перемещу ее в блок, который видите отделен в отдельном пункте, вот так она выглядит, мы иконку менять не буду, опять же вам уже об этом говорил. Захотите подготовить свой какой-то проект, можете нарисовать свои иконки либо поискать в интернете.
Так мы перезапустим проект, посмотрим, что у нас изменилась, и у нас произошли изменения. Итак проект перезапустился, откроем меню и как видим, добавился наш пункт.
Естественно сейчас он не обрабатывает нажатие на кнопку
Давайте сейчас напишем небольшую процедуру, в которой вместо текста «Hello Word!» будет написано, какая кнопка, какой пункт был нажат.
Файл content_main.xml
Для этого в TextView добавим ID, чтобы можно было к нему обращаться программно, я назову его nav_tv.
В файле MainActivity.java мы объявим переменную TextView tv перед функцией onCreate, также нам нужно будет найти ее через findViewById() и я надеюсь вы уже знаете, как это делается и объяснять вам не надо.
tv=findViewById(R.id.nav_tv);
теперь найдем конструкцию onNavigationItemSelected и в конструкцию if..else допишем
tv.setText()
и укажем текст который будет появляться в центре нашего приложения по нажатию на кнопку.
Соответственно, для пункта nav_camera, который мы назвали почему-то импорт, потому как на иконке изображен фотоаппарат, мы назовем это действие «Нажата кнопка: Камера», «Нажата кнопка: Галерея»
public boolean onNavigationItemSelected(MenuItem item) < // Handle navigation view item clicks here. int (id == R.id.nav_camera) < // Handle the camera action tv.setText("Нажата кнопка: Импорт"); >else if (id == R.id.nav_gallery) < tv.setText("Нажата кнопка: Галерея"); >else if (id == R.id.nav_slideshow) < tv.setText("Нажата кнопка: Слайдшоу"); >else if (id == R.id.nav_manage)
Здесь может находиться какая либо процедура, то есть необязательно просто вот одно действие, прямое, сразу передать текст куда то туда то и все, то есть здесь можно вызвать, допустим, дополнительную активность, а скорее всего так вы будете делать, если вы этим интересуетесь, либо фрагмент какой-то откроется, либо новая активность.
Потому здесь достаточно богатое поле для деятельности, вспомните хотя бы приложение для aliexpress, сколько там пунктов находится всевозможных: магазин, купите, избранное, поделиться и настройки. Кстати, тут есть — инструменты это в принципе почти как настройки.
Обратите внимание — я добавил функцию finish() , она закроет приложение по нажатию на этот пункт.
else if (id == R.id.nav_exit)
Перезапустили проект и теперь как вы видите при нажатии на пункты меню,(исправлю камера на импорт)можно будет видеть, что наше боковое меню реагирует на воздействие нажмем на выход и приложение закрылось.
Сейчас немного займемся настройкой декоративного элемента, который у нас отвечает за рисунок и за градиент.
Градиент в side_nav_bar
В файле side_nav_bar прописан градиент который находится как background возле картинки.
Есть центральный цвет, есть начальный цвет, есть конечный цвет и есть угол на который будет повёрнут градиент.
Я специально не подбирал цвета которые хотел бы поставить сюда ну пока просто в виде эксперимента я вам покажу как это все меняется, как настраивается.
Если вы будете уже серьезно заниматься, разрабатывать свой собственный стиль приложение вы уже конкретно эти шестнадцатеричные цвета подберете, потому как я пока гадаю на кофейной гуще, если можно так выразиться.)))
Так изменим угол 135 градусов на 90, и через некоторое время некоторой задержкой обновляется наш градиент и вот сейчас картинка у нас под наклоном, и соответственно, обновилось приложение, и наше меню, изменился в макете наш градиент.
В принципе, можете подобрать любой переход, от светлого тона к тёмному цвету, либо посередине, чтобы барьер был.
Можно в принципе поиграться с углом наклона, у вас изменится вид этой шапки, или сделать однотонный цвет, допустим красный — red или #FF0000
Необязательно использовать градиент, можно указать начальный и конечный одинаковый цвет.
Давайте перенесем нашу кнопку выход и удалим часть, вот этот блок можно удалить, вместе с разделителем. Вот у нас получится вот такое меню сокращенное. Не обязательно делать либо вы можете добавлять, удалять пункты. Поскольку я удалил часть элементов, то мне нужно подправить код обработчика нажатия на пункты.
Перезапустим наше приложение, обновилось нашими меню, так оно аккуратно, компактно, если у вас пока много пунктов нет – можете ограничиться небольшим списком.
Смотрите видео Android Studio: Как сделать боковое меню с помощью NavigationDrawer:
Рекомендуем смотреть видео в полноэкранном режиме, в настойках качества выбирайте 1080 HD, не забывайте подписываться на канал в YouTube, там Вы найдете много интересного видео, которое выходит достаточно часто. Приятного просмотра!
С уважением, авторы сайта Компьютерапия
Понравилась статья? Поделитесь ею с друзьями и напишите отзыв в комментариях!
Связанные статьи
- Android Studio: получение JSON в ListView с сервера на хостинге. Урок № 3 — (видео) — 06/12/2020 19:10
- Android Studio: получение JSON в ListView и ArrayAdapter. Урок № 2 — (видео) — 06/12/2020 19:08
- Android Studio: получение JSON в RecyclerView и CardView. Урок № 1 — (видео) — 06/12/2020 19:04
- Android Studio: получение JSON в ListView с сервера на хостинге. Урок № 3 — 04/12/2020 21:46
- Android Studio: получение JSON в ListView и ArrayAdapter. Урок № 2 — 04/12/2020 20:39
- Android Studio: получение JSON в RecyclerView и CardView. Урок № 1 — 04/12/2020 19:40
- Как подключить php mysql к эмулятору android. Локальный сервер и android studio — (видео) — 17/05/2020 13:04
- Как запустить LDPlayer в Android Studio — (видео) — 11/03/2020 16:53
- JS база данных и ANDROID STUDIO. Часть 3 — (видео) — 15/12/2019 06:54
- JS база данных и ANDROID STUDIO. Часть 3 — 15/12/2019 06:40
- Установка android studio и настройка SDK на VirtualBox с нуля — 19/01/2019 11:52
- Установка android studio и настройка SDK на VirtualBox с нуля — (видео) — 21/10/2018 17:27
- Android Studio Как сделать виджет игру Орел или решка — (видео) — 28/04/2018 19:02
- Android Studio Navigation Drawer как сделать боковое меню — (видео) — 28/04/2018 18:58
- Android studio Android Menu, как сделать меню андроид — (видео) — 28/04/2018 18:55
- Ответы на вопросы как сделать приложение расписание уроков для андроид в Android Studio — (видео) — 28/04/2018 18:09
- Android Studio Как сделать виджет — игру Орел или решка — 08/04/2018 19:38
- Создание расписания уроков для андроид устройств. Часть 2. База данных SQLITE и фрагменты — 13/12/2017 19:49
- Создание фрагментов и использование вкладок для Android — (видео) — 19/11/2017 07:32
- Создание фрагментов и использование вкладок для Android — 19/11/2017 05:16
Новые статьи
- Android приложение для начинающих гитаристов, пишем андроид приложение с аккордами для гитары — 05/09/2021 13:14
- Android Studio: получение JSON из базы данных с помощью PHP. Урок № 4 — 21/02/2021 07:12
- Android Studio: получение JSON в ListView с сервера на хостинге. Урок № 3 — 04/12/2020 21:46
- Android Studio: получение JSON в ListView и ArrayAdapter. Урок № 2 — 04/12/2020 20:39
- Android Studio: получение JSON в RecyclerView и CardView. Урок № 1 — 04/12/2020 19:40
- JS база данных и ANDROID STUDIO. Часть 3 — 15/12/2019 06:40
- Уведомления — Notifications в Android Studio — 16/04/2019 18:14
- Блютуз подключение в Android (проект для Arduino). Часть 1. — 12/04/2019 17:14
- Установка android studio и настройка SDK на VirtualBox с нуля — 19/01/2019 11:52
- Android Studio Как сделать виджет — игру Орел или решка — 08/04/2018 19:38
Предыдущие статьи
- Android Menu, как сделать меню андроид — 08/03/2018 14:44
- Создание подписанного приложения для android. Generate Signed APK. — 17/02/2018 09:50
- Android and Jsoup. Парсим вебсайт на вордпрессе. Расписание уроков — часть 3 — 15/01/2018 18:25
- Создание расписания уроков для андроид устройств. Часть 2. База данных SQLITE и фрагменты — 13/12/2017 19:49
- Создание расписания уроков для андроид устройств. Array Adapter для фрагментов. — 06/12/2017 15:07
- Создание фрагментов и использование вкладок для Android — 19/11/2017 05:16
- SplashScreen в Android: пишем заставку — 18/08/2017 19:06
- Диалог в андроид: пишем приложение в Android Studio — 13/08/2017 11:27
- Intent — Android приложение с несколькими Activity — 17/06/2017 17:05
- Создание списка ListView и ArrayAdapter в Android Studio — 09/06/2017 20:38
- Используем SharedPreferences для android — 05/05/2017 18:01
- Toast в Android Studio: пишем приложение с сообщениями — 04/05/2017 17:38
- Приложение-браузер для android устройств — 03/03/2017 16:56
- Android приложение за 5 минут. Часть 2 — 03/03/2017 16:33
- Создать андроид приложение за 5 минут — 22/11/2016 18:08
- Создание эмулятора Android, настройка AVD — 04/09/2016 15:19
- Установка Android Studio, настройка SDK — 04/09/2016 12:04
- Как начать программировать начинающим пользователям для андроид — 04/09/2016 10:28