Vue par défaut du tiroir de navigation vers ExpandableListView
Dans Android Studio 2.1.2, si je crée une activité de navigation par défaut, j'obtiens cette vue:
Qui utilise le fichier activity_main.xml
Suivant:
<?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"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
<Android.support.design.widget.NavigationView
Android:id="@+id/nav_view"
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</Android.support.v4.widget.DrawerLayout>
Comme vous pouvez le voir, <Android.support.design.widget.NavigationView/>
Utilise app:menu="@menu/activity_main_drawer"
Pour afficher la liste des menus définis dans le fichier activity_main_drawer.xml
Comme suit:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:Android="http://schemas.Android.com/apk/res/Android">
<group Android:checkableBehavior="single">
<item
Android:id="@+id/nav_camera"
Android:icon="@drawable/ic_menu_camera"
Android:title="Import" />
<item
Android:id="@+id/nav_gallery"
Android:icon="@drawable/ic_menu_gallery"
Android:title="Gallery" />
<item
Android:id="@+id/nav_slideshow"
Android:icon="@drawable/ic_menu_slideshow"
Android:title="Slideshow" />
<item
Android:id="@+id/nav_manage"
Android:icon="@drawable/ic_menu_manage"
Android:title="Tools" />
</group>
<item Android:title="Communicate">
<menu>
<item
Android:id="@+id/nav_share"
Android:icon="@drawable/ic_menu_share"
Android:title="Share" />
<item
Android:id="@+id/nav_send"
Android:icon="@drawable/ic_menu_send"
Android:title="Send" />
</menu>
</item>
</menu>
Maintenant, mon plan est de remplacer cette liste de menu définie dans activity_main_drawer.xml
Et d'utiliser à la place un ExpandableListView
. Parce que je veux que mes éléments de menu aient des sous-catégories, par exemple, l'élément de menu Cars
aura une sous-catégorie de Diesel
, Petrol
et Hybrid
etc. J'ai fait des recherches et il semble que personne n'a la solution de travail exacte dont j'ai besoin.
J'ai regardé ici:
- Les tutoriels ouverts
- Implémentez expandablelistview dans l'activité du tiroir de navigation faite par Android studio
- Android: 2 ou plus ExpandableListView dans le tiroir de navigation
- Comment créer une liste extensible dans le tiroir de navigation?
et les liens ultérieurs qui y sont mentionnés.
NB: Les liens ci-dessus mentionnent l'utilisation de ListView
dans le tiroir de navigation, ce qui n'est plus le cas comme Android Studio y parvient en utilisant menu
item en utilisant activity_main_drawer.xml
.
Quelqu'un peut-il me fournir un exemple pratique de cela? Pour réitérer, je veux une vue de liste extensible à l'intérieur de l'activité du tiroir de navigation par défaut. J'ai compris que j'aurais besoin de fichiers XML et de codes de classe Java pour me donner les bases dont j'ai besoin pour commencer).
Merci d'avance. :)
EDIT: Maquette du look final (excusez mes compétences Photoshop)
Mon approche actuelle consiste à créer une nouvelle mise en page ex_list
Comme suit:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical" Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v4.widget.DrawerLayout
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<ExpandableListView
Android:id="@+id/lvExp"
Android:layout_height="match_parent"
Android:layout_width="match_parent"/>
</Android.support.v4.widget.DrawerLayout>
</LinearLayout>
et modifiez activity_main.xml
pour
<?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"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
<Android.support.design.widget.NavigationView
Android:id="@+id/nav_view"
Android:layout_width="240dp"
Android:layout_gravity = "start"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main">
<include
layout="@layout/ex_list"
Android:layout_height="wrap_content"
Android:layout_width="match_parent"/>
</Android.support.design.widget.NavigationView>
</Android.support.v4.widget.DrawerLayout>
Ce qui se traduit par la mise en page suivante:
et message d'erreur de
Java.lang.IllegalArgumentException: DrawerLayout must be measured with MeasureSpec.EXACTLY.
at Android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.Java:1036)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.Java:1465)
at Android.widget.LinearLayout.measureVertical(LinearLayout.Java:748)
at Android.widget.LinearLayout.onMeasure(LinearLayout.Java:630)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:194)
at Android.support.design.widget.NavigationView.onMeasure(NavigationView.Java:223)
at Android.view.View.measure(View.Java:18788)
at Android.support.v4.widget.DrawerLayout.onMeasure(DrawerLayout.Java:1104)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:194)
at Android.support.v7.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.Java:135)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.Java:1465)
at Android.widget.LinearLayout.measureVertical(LinearLayout.Java:748)
at Android.widget.LinearLayout.onMeasure(LinearLayout.Java:630)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:194)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.Java:1465)
at Android.widget.LinearLayout.measureVertical(LinearLayout.Java:748)
at Android.widget.LinearLayout.onMeasure(LinearLayout.Java:630)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewGroup.measureChildWithMargins(ViewGroup.Java:5951)
at Android.widget.FrameLayout.onMeasure(FrameLayout.Java:194)
at com.Android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.Java:2643)
at Android.view.View.measure(View.Java:18788)
at Android.view.ViewRootImpl.performMeasure(ViewRootImpl.Java:2100)
at Android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.Java:1216)
at Android.view.ViewRootImpl.performTraversals(ViewRootImpl.Java:1452)
at Android.view.ViewRootImpl.doTraversal(ViewRootImpl.Java:1107)
at Android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.Java:6013)
at Android.view.Choreographer$CallbackRecord.run(Choreographer.Java:858)
at Android.view.Choreographer.doCallbacks(Choreographer.Java:670)
at Android.view.Choreographer.doFrame(Choreographer.Java:606)
at Android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.Java:844)
at Android.os.Handler.handleCallback(Handler.Java:739)
at Android.os.Handler.dispatchMessage(Handler.Java:95)
at Android.os.Looper.loop(Looper.Java:148)
at Android.app.ActivityThread.main(ActivityThread.Java:5417)
at Java.lang.reflect.Method.invoke(Native Method)
at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:726)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:616)
Qu'est-ce que je fais mal?
RÉPONDRE:
Merci @Moulesh !!!
Voici le code de l'adaptateur de liste extensible:
public class ExpandListAdapter extends BaseExpandableListAdapter {
private Context _context;
private List<String> _listDataHeader; // header titles
// child data in format of header title, child title
private HashMap<String, List<String>> _listDataChild;
public ExpandListAdapter(Context context, List<String> listDataHeader,
HashMap<String, List<String>> listChildData) {
this._context = context;
this._listDataHeader = listDataHeader;
this._listDataChild = listChildData;
}
@Override
public Object getChild(int groupPosition, int childPosititon) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition))
.get(childPosititon);
}
@Override
public long getChildId(int groupPosition, int childPosition) {
return childPosition;
}
@Override
public View getChildView(int groupPosition, final int childPosition,
boolean isLastChild, View convertView, ViewGroup parent) {
final String childText = (String) getChild(groupPosition, childPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_item, null);
}
TextView txtListChild = (TextView) convertView
.findViewById(R.id.lblListItem);
txtListChild.setText(childText);
return convertView;
}
@Override
public int getChildrenCount(int groupPosition) {
return this._listDataChild.get(this._listDataHeader.get(groupPosition))
.size();
}
@Override
public Object getGroup(int groupPosition) {
return this._listDataHeader.get(groupPosition);
}
@Override
public int getGroupCount() {
return this._listDataHeader.size();
}
@Override
public long getGroupId(int groupPosition) {
return groupPosition;
}
@Override
public View getGroupView(int groupPosition, boolean isExpanded,
View convertView, ViewGroup parent) {
String headerTitle = (String) getGroup(groupPosition);
if (convertView == null) {
LayoutInflater infalInflater = (LayoutInflater) this._context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = infalInflater.inflate(R.layout.list_group, null);
}
TextView lblListHeader = (TextView) convertView
.findViewById(R.id.lblListHeader);
lblListHeader.setTypeface(null, Typeface.BOLD);
lblListHeader.setText(headerTitle);
return convertView;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public boolean isChildSelectable(int groupPosition, int childPosition) {
return true;
}}
Dans votre activité:
private void enableExpandableList() {
listDataHeader = new ArrayList<String>();
listDataChild = new HashMap<String, List<String>>();
expListView = (ExpandableListView) findViewById(R.id.left_drawer);
prepareListData(listDataHeader, listDataChild);
listAdapter = new ExpandListAdapter(this, listDataHeader, listDataChild);
// setting list adapter
expListView.setAdapter(listAdapter);
expListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
@Override
public boolean onGroupClick(ExpandableListView parent, View v,
int groupPosition, long id) {
// Toast.makeText(getApplicationContext(),
// "Group Clicked " + listDataHeader.get(groupPosition),
// Toast.LENGTH_SHORT).show();
return false;
}
});
// Listview Group expanded listener
expListView.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {
@Override
public void onGroupExpand(int groupPosition) {
Toast.makeText(getApplicationContext(),
listDataHeader.get(groupPosition) + " Expanded",
Toast.LENGTH_SHORT).show();
}
});
// Listview Group collasped listener
expListView.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() {
@Override
public void onGroupCollapse(int groupPosition) {
Toast.makeText(getApplicationContext(),
listDataHeader.get(groupPosition) + " Collapsed",
Toast.LENGTH_SHORT).show();
}
});
// Listview on child click listener
expListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {
@Override
public boolean onChildClick(ExpandableListView parent, View v,
int groupPosition, int childPosition, long id) {
// TODO Auto-generated method stub
// Temporary code:
// till here
Toast.makeText(
getApplicationContext(),
listDataHeader.get(groupPosition)
+ " : "
+ listDataChild.get(
listDataHeader.get(groupPosition)).get(
childPosition), Toast.LENGTH_SHORT)
.show();
return false;
}
});}
Méthode pour créer une liste avec des données:
private void prepareListData(List<String> listDataHeader, Map<String,
List<String>> listDataChild) {
// Adding child data
listDataHeader.add("Product1");
listDataHeader.add("product2");
listDataHeader.add("Product3");
// Adding child data
List<String> top = new ArrayList<String>();
top.add("x1");
top.add("x2");
top.add("x3");
top.add("x4");
top.add("x5");
List<String> mid = new ArrayList<String>();
mid.add("y1");
mid.add("y2");
mid.add("y3");
List<String> bottom = new ArrayList<String>();
bottom.add("z1");
bottom.add("z2");
bottom.add("z3");
listDataChild.put(listDataHeader.get(0), top); // Header, Child data
listDataChild.put(listDataHeader.get(1), mid);
listDataChild.put(listDataHeader.get(2), bottom);
}
ce code dans la mise en page xml
<?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"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/drawer_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
Android:id="@+id/act_bar"
layout="@layout/app_bar_main"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
<Android.support.design.widget.NavigationView
Android:id="@+id/nav_view"
Android:layout_width="wrap_content"
Android:layout_height="match_parent"
Android:layout_gravity="start"
Android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main">
<!--app:menu="@menu/activity_main_drawer"-->
<ExpandableListView
Android:id="@+id/left_drawer"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_marginTop="@dimen/nav_header_height"
Android:background="@color/Background"
Android:dividerHeight="0dp" />
</Android.support.design.widget.NavigationView>
</Android.support.v4.widget.DrawerLayout>
xml pour ExplistHeader list_group.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:orientation="vertical"
Android:paddingTop="10dp"
Android:padding="30dp"
Android:background="@color/Background">
<TextView
Android:id="@+id/lblListHeader"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:paddingLeft="?
Android:attr/expandableListPreferredItemPaddingLeft"
Android:textSize="17dp"
Android:textColor="@color/colorTextPrimary" />
</LinearLayout>
xml pour Explistchild list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="55dip"
Android:background="@color/Background"
Android:orientation="vertical" >
<TextView
Android:id="@+id/lblListItem"
Android:layout_width="fill_parent"
Android:layout_height="wrap_content"
Android:textSize="17dip"
Android:paddingTop="5dp"
Android:paddingBottom="5dp"
Android:paddingLeft="?
Android:attr/expandableListPreferredChildPaddingLeft" />
</LinearLayout>
Téléchargez le code source d'ici ( tiroir de navigation avec expandablelistview dans Android )
import Android.content.Context;
import Android.view.LayoutInflater;
import Android.view.View;
import Android.view.ViewGroup;
import Android.widget.BaseExpandableListAdapter;
import Android.widget.TextView;
import Java.util.ArrayList;
public class CountryAdapter extends BaseExpandableListAdapter {
Context context;
ArrayList<Model_country> al_country;
public CountryAdapter(Context context, ArrayList<Model_country> al_country) {
this.context = context;
this.al_country = al_country;
}
@Override
public int getGroupCount() {
return al_country.size();
}
@Override
public int getChildrenCount(int i) {
return al_country.get(i).getAl_state().size();
}
@Override
public Object getGroup(int i) {
return al_country.get(i);
}
@Override
public Object getChild(int i, int i1) {
return al_country.get(i).getAl_state().get(i1);
}
@Override
public long getGroupId(int i) {
return i;
}
@Override
public long getChildId(int i, int i1) {
return i1;
}
@Override
public boolean hasStableIds() {
return false;
}
@Override
public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
if (view==null){
LayoutInflater layoutInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.adapter_header, null);
}
TextView tv_state = (TextView)view.findViewById(R.id.tv_name);
tv_state.setText(al_country.get(i).getStr_country());
return view;
}
@Override
public View getChildView(final int i, final int i1, boolean b, View view, ViewGroup viewGroup) {
if (view==null){
LayoutInflater layoutInflater = (LayoutInflater) this.context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = layoutInflater.inflate(R.layout.adapter_childview, null);
}
TextView tv_state = (TextView)view.findViewById(R.id.tv_name);
tv_state.setText(al_country.get(i).getAl_state().get(i1).getStr_name());
tv_state.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((MainActivity)context).fn_selectedPosition(i,i1);
}
});
return view;
}
@Override
public boolean isChildSelectable(int i, int i1) {
return false;
}
}
Merci!