На днях для одного из разрабатываемого нашей командой приложения, заказчик внес правку в дизайн, которая требовала разработать выдвижное меню с довольно не стандартным расположением view компонентов. Хотя на данный момент и существуют различные виды реализации данной задачи, они оказывались либо слишком объемными, либо не предоставляли реализацию нужного функционала.
Обдумав некоторое время данную задачу, я решил реализовать данное меню на основе стандартного компонента DrawerLayout, в основу которого было вложено 2 root элемента — RelativeLayout для основной разметки окна, а также еще один RelativeLayout как контейнер для бокового меню. Хотелось бы добавить, что именно 2 root элемента должно быть внутри DrawerLayout, подробнее об этом контейнере можно прочесть в официальной документации гугла.
Разметка основной activity готова, теперь приступим к написанию класса, который будет выполнять основную логику. Создадим класс, наследующий RelativeLayout. Данный класс реализует всю логику нашего меню, в том числе устанавливает разметку и определяет все view.
В конструктор следует передать context и parent.
parent — RelativeLayout, который был объявлен в разметке для основной activity ( )
Далее функция initView(final Context context,RelativeLayout parent) — надувает основную разметку, которая будет помещена в выдвижное меню, а также определим тут все view компоненты и их слушатели.
В R.layout.view_drawer_layout для примера я объявил всего одну кнопку.
На данном этапе основная часть готова, осталось лишь добавить наш NavigationLayout при помощи addView к основному parent контейнеру.
Создадим класс, наследующий AppCompactActivity
Данный класс переопределяет стандартный метод setContentView, добавляя в него вызов функции, которая 'инициализирует' выдвижное меню. Также здесь мы создаем объект ранее написанного нами NavigationLayout класса и добавляем его при помощи left_drawer.addView(navigationLayout) к родителю, который и является контейнером бокового меню.
Осталось дело за малым — чтобы все заработало, нужно лишь создать экран (activity) и унаследовать ParentNavigationActivity, который мы только что создали.
Таким образом, при наследовании ParentNavigationActivity и вызове функции setContentView, в нашей activity появляется готовое меню.

Хотелось бы добавить, что 2 контейнера, лежащих в основе DrawerLayout, необязательно должны быть RelativeLayout. Вместо них можно использовать constraintlayout, framelayout, linearlayout и другие.
Данный способ является довольно простым в реализации, а также гибким в плане добавления меню к любым activity. Надеюсь что данная статья поможет android разработчикам упростить создание бокового меню для своих приложений.
Обдумав некоторое время данную задачу, я решил реализовать данное меню на основе стандартного компонента DrawerLayout, в основу которого было вложено 2 root элемента — RelativeLayout для основной разметки окна, а также еще один RelativeLayout как контейнер для бокового меню. Хотелось бы добавить, что именно 2 root элемента должно быть внутри DrawerLayout, подробнее об этом контейнере можно прочесть в официальной документации гугла.
Реализация
Xml файл разметки для основной activity
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Основной контейнер разметки --> </RelativeLayout> <!-- Контейнер, содержащий выдвижное меню --> <RelativeLayout android:id="@+id/left_drawer" android:layout_width="300dp" android:layout_height="match_parent" android:layout_gravity="start" android:choiceMode="none" <!-- обязательно добавляем данный атрибут, иначе все, что находится под выдвинутым меню будет кликабельно, даже если нажимать на элементы самого меню --> android:clickable="true" android:background="#FFFFFF" xmlns:android="http://schemas.android.com/apk/res/android" /> </android.support.v4.widget.DrawerLayout>
Разметка основной 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 для примера я объявил всего одну кнопку.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="300dp" android:background="@color/screen_background" android:layout_height="match_parent"> <Button android:layout_width="110dp" android:layout_height="55dp" android:textAllCaps="false" android:id="@+id/ok" android:text="Next" android:textStyle="bold" android:textSize="25sp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:textColor="@color/buttonTextColor" /> </RelativeLayout>
На данном этапе основная часть готова, осталось лишь добавить наш 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 разработчикам упростить создание бокового меню для своих приложений.
