【Android】侧滑菜单的实现方式

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_38950819/article/details/82744469

对于侧滑菜单的实现方式,一种比较标准化的实现方式是DrawerLayout + NavigationView的方式,该方式的实现过程可以看我的另一篇博客【Android】Material Design 之三 NavigationView 使用 。然而,DrawerLayout + NavigationView的侧滑实现有个缺点就是,菜单的布局是单一的,只有一个图标、一个标题,当我们想要实现丰富的菜单布局时(如下图所示)该方法就不能满足我们的需要,此时,我们需要考虑如何让侧滑的菜单能有丰富样式的布局,本篇博客就来解决这个问题。

 实现上图中左右两种样式的侧滑菜单,同样需要DrawerLayout布局的支持,DrawerLayout布局中可有3个子布局,第一个布局必须为主界面,其他2个布局就是左、右两侧的布局,左右两个只放一个也可以。

这里我们在布局中左右两侧布局都使用,可以同时分别在左右两边布局中实现上图中两种侧滑菜单样式,只需要在2个子布局添加属性android:layout_gravity,值为start从左测滑出菜单,值为end从右侧滑出菜单。

上图中,左边是使用列表ListView控件实现菜单样式,右边是用网格GridView控件实现菜单样式,上方都是一个头布局。

布局文件:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyMenuViewActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="这是自定义侧滑菜单"/>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layout_gravity="start">

        <include layout="@layout/header"/>

        <ListView
            android:id="@+id/lv"
            android:background="#ffffff"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="#cacaca"
            android:dividerHeight="2dp"
            android:scrollbars="none">
        </ListView>
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layout_gravity="end">

        <include layout="@layout/header"/>

        <GridView
            android:id="@+id/gv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scrollbars="none"
            android:numColumns="2"
            android:background="#808080"
            android:horizontalSpacing="2dp"
            android:verticalSpacing="2dp">
        </GridView>

    </LinearLayout>
</android.support.v4.widget.DrawerLayout>

头布局header.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="180dp"
    android:orientation="vertical"
    android:gravity="center"
    android:background="@drawable/header_bg">

    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@drawable/avator"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="摸爬滚打的程序媛"
        android:padding="5dp"
        android:textColor="#FFFFFF"/>
</LinearLayout>

头布局中的背景 header_bg.xml:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <gradient android:type="linear"
        android:angle="45"
        android:startColor="#e965d3"
        android:endColor="#ac68e7"/>
</shape>

 listview_item.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_centerVertical="true"/>

    <TextView
        android:id="@+id/tv"
        android:layout_toRightOf="@+id/iv"
        android:layout_marginLeft="5dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="15sp"
        android:textColor="#000000"
        android:layout_centerVertical="true"/>

    <ImageView
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_arrow_right"
        android:layout_centerVertical="true"/>

</RelativeLayout>

 gridview_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="match_parent"
    android:padding="20dp"
    android:orientation="vertical"
    android:gravity="center"
    android:background="#FFFFFF">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="50dp"
        android:layout_height="50dp" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="15sp"
        android:textColor="#000000"/>
</LinearLayout>

既然使用了列表,就需要适配器进行数据的填充,自定义可复用的适配器MyBaseAdapter.java:

public abstract class MyBaseAdapter<T> extends BaseAdapter{

    private List<T> dataList;
    private int layoutResId;    //列表item的布局id

    public MyBaseAdapter(List<T> dataList,int layoutResId) {
        this.dataList = dataList;
        this.layoutResId=layoutResId;
    }

    //获取数据个数
    @Override
    public int getCount() {
        return dataList != null ? dataList.size() : 0;
    }

    //获取指定位置的数据
    @Override
    public Object getItem(int i) {
        return dataList.get(i);
    }

    //获取指定位置下标
    @Override
    public long getItemId(int i) {
        return i;
    }

    //获取item布局
    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        ViewHolder viewHolder=ViewHolder.bind(viewGroup.getContext(),view,viewGroup,layoutResId,i);
        bindView(viewHolder,dataList.get(i));
        return viewHolder.getItemView();
    }

    public abstract void bindView(ViewHolder holder,T data);

    public static class ViewHolder{

        private SparseArray<View> views;    //存放ListView的子项item中的控件view
        private View convertView;           //存放convertView
        private int position;               //游标
        private Context context;            //上下文

        //构造方法,完成相关初始化
        private ViewHolder(Context context,ViewGroup parent,int layoutResId){
            views=new SparseArray<>();
            this.context=context;
            convertView=LayoutInflater.from(context).inflate(layoutResId,parent,false);
            convertView.setTag(this);
        }


        //绑定ViewHolder和Item
        public static ViewHolder bind(Context context,View convertView,ViewGroup parent,int layoutResId,int position){
            ViewHolder viewHolder;
            if(convertView==null){
                viewHolder=new ViewHolder(context,parent,layoutResId);
            }else{
                viewHolder= (ViewHolder) convertView.getTag();
                viewHolder.convertView=convertView;
            }
            viewHolder.position=position;
            return viewHolder;
        }

        //根据id获取集合中保存的控件
        @SuppressWarnings("unchecked")
        private <T extends View> T getView(int resId){
            T t= (T) views.get(resId);
            if(t==null){
                t=convertView.findViewById(resId);
                views.put(resId,t);
            }
            return t;
        }

        //获取子项的View
        public View getItemView(){
            return convertView;
        }

        //获取子项位置
        public int getItemPosition(){
            return position;
        }


        //文本控件 设置文字
        public void setText(int resId, CharSequence text){
            View view=getView(resId);
            if (view instanceof TextView) {
                ((TextView) view).setText(text);
            }
        }

        //图片控件或者可设置背景图片的控件 设置图片
        public void setImageResource(int resId, int drawableResId){
            View view=getView(resId);
            if (view instanceof ImageView) {
                ((ImageView) view).setImageResource(drawableResId);
            }else{
                view.setBackgroundResource(drawableResId);
            }
        }

        //可监听控件 设置点击监听
        public ViewHolder setOnClickListener(int resId,View.OnClickListener listener){
            getView(resId).setOnClickListener(listener);
            return this;
        }

        //控件设置可见
        public ViewHolder setVisibility(int resId,int visible){
            getView(resId).setVisibility(visible);
            return this;
        }

        //设置标签
        public ViewHolder setTag(int resId,Object obj){
            getView(resId).setTag(obj);
            return this;
        }

        //其他方法可自行扩展
    }
}

 定义填充的数据bean:

public class MenuBean {
    private int imgResId;
    private String title;

    public MenuBean(int imgResId, String title) {
        this.imgResId = imgResId;
        this.title = title;
    }

    public int getImgResId() {
        return imgResId;
    }

    public void setImgResId(int imgResId) {
        this.imgResId = imgResId;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}

 代码如下:

public class MyMenuViewActivity extends AppCompatActivity {
    private ListView listView;
    private GridView gridView;
    private MyBaseAdapter<MenuBean> lvAdapter;
    private MyBaseAdapter<MenuBean> gvAdapter;
    private List<MenuBean> list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_snavigation_view);

        listView=findViewById(R.id.lv);
        gridView=findViewById(R.id.gv);

        //数据源
        list=new ArrayList<>();
        list.add(new MenuBean(R.drawable.ic_menu_book,"头条"));
        list.add(new MenuBean(R.drawable.ic_menu_star,"收藏"));
        list.add(new MenuBean(R.drawable.ic_menu_argu,"论坛"));
        list.add(new MenuBean(R.drawable.ic_menu_load,"下载"));
        list.add(new MenuBean(R.drawable.ic_menu_rili,"日历"));
        list.add(new MenuBean(R.drawable.ic_menu_level,"等级"));
        list.add(new MenuBean(R.drawable.ic_menu_cloud,"云空间"));
        list.add(new MenuBean(R.drawable.ic_menu_help,"帮助"));

        lvAdapter=new MyBaseAdapter<MenuBean>(list,R.layout.listview_item) {
            @Override
            public void bindView(ViewHolder holder, MenuBean data) {
                holder.setImageResource(R.id.iv,data.getImgResId());
                holder.setText(R.id.tv,data.getTitle());
            }
        };

        gvAdapter=new MyBaseAdapter<MenuBean>(list,R.layout.gridview_item) {
            @Override
            public void bindView(ViewHolder holder, MenuBean data) {
                holder.setImageResource(R.id.iv,data.getImgResId());
                holder.setText(R.id.tv,data.getTitle());
            }
        };

        listView.setAdapter(lvAdapter);
        gridView.setAdapter(gvAdapter);
    }
}

 运行效果就如开始的那张图,ListView的分割线可以通过下面两个属性实现:

android:divider="#cacaca"     //分割线颜色
android:dividerHeight="2dp"   //分割线高度

GridView的分割线实现,首先在设置其item背景,然后在其控件中 设置下面三个属性:

android:background="#808080"    //GridView背景颜色
android:horizontalSpacing="2dp" //列之间的水平间隔
android:verticalSpacing="2dp    //行之间的垂直间隔

这里再补充说一下,使用ListView实现侧滑菜单时,除了可以在布局中添加头布局

<include layout="@layout/snavigation_view_header"/>,还可以使用listview.addHeaderView()方法添加头文件,效果和在布局中添加的效果有些不同,如下图:

View view=LayoutInflater.from(this).inflate(R.layout.header,null);
listView.addHeaderView(view);

 

猜你喜欢

转载自blog.csdn.net/qq_38950819/article/details/82744469