• Android 自己实现 NavigationView [Design Support Library(1)]


    转载请标明出处:
    http://blog.csdn.net/lmj623565791/article/details/46405409
    本文出自:【张鸿洋的博客】

    一、概述

    Google I/O 2015 给大家带来了Android Design Support Library。对于希望做md风格的app的来说,简直是天大的喜讯了~大家能够通过Android Design Support Library该文章对其进行了解,也能够直接在github上下载演示样例代码执行学习。为了表达我心中的喜悦,我决定针对该库写一系列的文章来分别介绍新添加的控件。

    ok,那么首先介绍的就是NavigationView。

    注意下更新下as的SDK,然后在使用的过程中,在build.gradle中加入:

    compile 'com.android.support:design:22.2.0'

    在md风格的app中,比如例如以下风格的側滑菜单非经常见:

    在之前的设计中。你可能须要考虑怎样去布局实现,比如使用ListView;再者还要去设计Item的选中状态之类~~

    but,如今。google提供了NavigationView,你只须要写写布局文件。这种效果就ok了,而且兼容到Android 2.1。非常值得去体验一下。

    接下来我们来介绍怎样去使用这个NavigationView

    二、使用

    使用起来very simple ,主要就是写写布局文件~

    (一)布局文件

    <?xml version="1.0" encoding="utf-8"?

    > <android.support.v4.widget.DrawerLayout android:id="@+id/id_drawer_layout" 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" android:fitsSystemWindows="true" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/id_toolbar" android:layout_width="match_parent" android:layout_height="?

    attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <TextView android:id="@+id/id_tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="HelloWorld" android:textSize="30sp"/> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/id_nv_menu" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="left" android:fitsSystemWindows="true" app:headerLayout="@layout/header_just_username" app:menu="@menu/menu_drawer" /> </android.support.v4.widget.DrawerLayout>

    能够看到我们的最外层是DrawerLayout。里面一个content。一个作为drawer。我们的drawer为NavigationView


    注意这个view的两个属性app:headerLayout="@layout/header_just_username"app:menu="@menu/menu_drawer",分别代表drawer布局中的header和menuitem区域。当然你能够依据自己的情况使用。

    接下来看看header的布局文件和menu配置文件:

    
    <?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="192dp"
                    android:background="?attr/colorPrimaryDark"
                    android:orientation="vertical"
                    android:padding="16dp"
                    android:theme="@style/ThemeOverlay.AppCompat.Dark">
    
    
        <TextView
            android:id="@+id/id_link"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="16dp"
            android:text="http://blog.csdn.net/lmj623565791"/>
    
        <TextView
            android:id="@+id/id_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/id_link"
            android:text="Zhang Hongyang"/>
    
        <ImageView
            android:layout_width="72dp"
            android:layout_height="72dp"
            android:layout_above="@id/id_username"
            android:layout_marginBottom="16dp"
            android:src="@mipmap/icon"/>
    
    
    </RelativeLayout>
    
    <?

    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_home" android:icon="@drawable/ic_dashboard" android:title="Home"/> <item android:id="@+id/nav_messages" android:icon="@drawable/ic_event" android:title="Messages"/> <item android:id="@+id/nav_friends" android:icon="@drawable/ic_headset" android:title="Friends"/> <item android:id="@+id/nav_discussion" android:icon="@drawable/ic_forum" android:title="Discussion"/> </group> <item android:title="Sub items"> <menu> <item android:icon="@drawable/ic_dashboard" android:title="Sub item 1"/> <item android:icon="@drawable/ic_forum" android:title="Sub item 2"/> </menu> </item> </menu>

    别放错目录哈~

    布局文件写完了,基本就好了,是不是非常爽~看似复杂的效果,写写布局文件就ok。

    ps:默认的颜色非常多是从当前的主题中提取的。比方icon的stateColor,当然你也能够通过以下属性改动部分样式:

    app:itemIconTint=""
    app:itemBackground=""
    app:itemTextColor=""

    (二)Activity

    最后是Activity:

    package com.imooc.testandroid;
    
    import android.os.Bundle;
    import android.support.design.widget.NavigationView;
    import android.support.v4.widget.DrawerLayout;
    import android.support.v7.app.ActionBar;
    import android.support.v7.app.ActionBarActivity;
    import android.support.v7.widget.Toolbar;
    import android.view.MenuItem;
    
    
    public class NavigationViewActivity extends ActionBarActivity
    {
    
        private DrawerLayout mDrawerLayout;
        private NavigationView mNavigationView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_navigation_view);
    
            mDrawerLayout = (DrawerLayout) findViewById(R.id.id_drawer_layout);
            mNavigationView = (NavigationView) findViewById(R.id.id_nv_menu);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.id_toolbar);
            setSupportActionBar(toolbar);
    
            final ActionBar ab = getSupportActionBar();
            ab.setHomeAsUpIndicator(R.drawable.ic_menu);
            ab.setDisplayHomeAsUpEnabled(true);
    
            setupDrawerContent(mNavigationView);
    
    
        }
    
        private void setupDrawerContent(NavigationView navigationView)
        {
            navigationView.setNavigationItemSelectedListener(
    
                    new NavigationView.OnNavigationItemSelectedListener()
                    {
    
                        @Override
                        public boolean onNavigationItemSelected(MenuItem menuItem)
                        {
                            menuItem.setChecked(true);
                            mDrawerLayout.closeDrawers();
                            return 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_navigation_view, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item)
        {
            if(item.getItemId() == android.R.id.home)
            {
                mDrawerLayout.openDrawer(GravityCompat.START);
                return true ;
            }
            return super.onOptionsItemSelected(item);
        }
    
    }
    

    我们在Activity里面能够通过navigationView去navigationView.setNavigationItemSelectedListener,当selected的时候。menuItem去setChecked(true)。

    别忘了设置theme~

    <resources>
    
        <!-- Base application theme. -->
        <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
            <!-- Customize your theme here. -->
        </style>
    
        <style name="Theme.DesignDemo" parent="Base.Theme.DesignDemo">
        </style>
    
        <style name="Base.Theme.DesignDemo" parent="Theme.AppCompat.Light.NoActionBar">
            <item name="colorPrimary">#673AB7</item>
            <item name="colorPrimaryDark">#512DA8</item>
            <item name="colorAccent">#FF4081</item>
            <item name="android:windowBackground">@color/window_background</item>
        </style>
    
    </resources>
    
    
    <color name="window_background">#FFF5F5F5</color>
    
     <activity
        android:name=".NavigationViewActivity"
        android:label="@string/title_activity_navigation_view"
        android:theme="@style/Theme.DesignDemo">
    </activity>
    

    ok。到此就搞定了~~

    不过存在一个问题,此时你假设点击Sub items里面的Sub item,假设你期望当前选中应该是Sub item。你会发现不起作用。那怎么办呢?

    (三)Sub Item支持Cheable

    这里能够改动menu的配置文件:

    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    
        <group>
            <item
                android:id="@+id/nav_home"
                android:checkable="true"
                android:icon="@drawable/ic_dashboard"
                android:title="Home"/>
            <item
                android:id="@+id/nav_messages"
                android:checkable="true"
                android:icon="@drawable/ic_event"
                android:title="Messages"/>
            <item
                android:id="@+id/nav_friends"
                android:checkable="true"
                android:icon="@drawable/ic_headset"
                android:title="Friends"/>
            <item
                android:id="@+id/nav_discussion"
                android:checkable="true"
                android:icon="@drawable/ic_forum"
                android:title="Discussion"/>
        </group>
    
        <item android:title="Sub items">
            <menu>
                <item
                    android:checkable="true"
                    android:icon="@drawable/ic_dashboard"
                    android:title="Sub item 1"/>
                <item
                    android:checkable="true"
                    android:icon="@drawable/ic_forum"
                    android:title="Sub item 2"/>
            </menu>
        </item>
    
    </menu>

    android:checkableBehavior="single"去掉,然后给每一个item项加入android:checkable="true"

    然后在代码中:

    navigationView.setNavigationItemSelectedListener(
    
                    new NavigationView.OnNavigationItemSelectedListener()
                    {
    
                        private MenuItem mPreMenuItem;
    
                        @Override
                        public boolean onNavigationItemSelected(MenuItem menuItem)
                        {
                            if (mPreMenuItem != null) mPreMenuItem.setChecked(false);
                            menuItem.setChecked(true);
                            mDrawerLayout.closeDrawers();
                            mPreMenuItem = menuItem;
                            return true;
                        }
                    });

    存一下preMenuItem。手动切换。

    效果:

    ok,哈~事实上这个还是參考链接2里面的一个评论说的~~

    到此使用方法就介绍完了有木有一点小激动~ 可是还有个问题。对于app,就像ActionBar最初的出现,一開始大家都欢欣鼓励,后来发现app中多数情况下须要去定制,尼玛。是不是忽然认为ActionBar太死板了,恶心死了(当然了如今有了ToolBar灵活度上好多了)对于上述NavigationView可能也会存在定制上的问题。比方我希望选中的Item左边有个高亮的竖线之类的效果。

    那么,针对于各种需求,想要能解决各种问题,最好的方式就是说对于NavigationView的效果自己能够实现。

    最好,我们就来看看NavigationView自己实现有多难?

    三、自己实现NavigationView效果

    事实上NavigationView的实现非常easy,一个ListView就能够了。甚至都不须要去自己定义,简单写一个Adapter即可了~~

    首先观察该图,有没有发现奇妙之处。恩,你肯定发现不了,由于我们做的太像了。

    事实上这个图就是我通过ListView写的一个~是不是和原版非常像(~哈~參考了源代码的实现,当然像。)

    接下来分析。假设说是ListView,那么Item的type肯定不止一种,那我们数一数种类:

    • 带图标和文本的
    • 不过文本的 Sub Items
    • 切割线

    你会说还有顶部那个。顶部是headview呀~~

    这么分析完毕,是不是瞬间认为没有难度了~

    (一)首先布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v4.widget.DrawerLayout
        android:id="@+id/id_drawer_layout"
        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"
        android:fitsSystemWindows="true"
        >
    
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.v7.widget.Toolbar
                android:id="@+id/id_toolbar"
                android:layout_width="match_parent"
                android:layout_height="?

    attr/actionBarSize" android:background="?

    attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <TextView android:id="@+id/id_tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="HelloWorld" android:textSize="30sp"/> </RelativeLayout> <ListView android:id="@+id/id_lv_left_menu" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="start" android:paddingTop="0dp" android:background="#ffffffff" android:clipToPadding="false" android:divider="@null" android:listSelector="?attr/selectableItemBackground" /> </android.support.v4.widget.DrawerLayout>

    布局文件上:和上文对照,我们只把NavigationView换成了ListView.

    以下注意了,一大波代码来袭.

    (二) Activity

    package com.imooc.testandroid;
    
    public class NavListViewActivity extends ActionBarActivity
    {
        private ListView mLvLeftMenu;
        private DrawerLayout mDrawerLayout;
    
    
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_nav_list_view);
    
            mDrawerLayout = (DrawerLayout) findViewById(R.id.id_drawer_layout);
            mLvLeftMenu = (ListView) findViewById(R.id.id_lv_left_menu);
    
            Toolbar toolbar = (Toolbar) findViewById(R.id.id_toolbar);
            setSupportActionBar(toolbar);
    
            final ActionBar ab = getSupportActionBar();
            ab.setHomeAsUpIndicator(R.drawable.ic_menu);
            ab.setDisplayHomeAsUpEnabled(true);
    
            setUpDrawer();
        }
    
        private void setUpDrawer()
        {
            LayoutInflater inflater = LayoutInflater.from(this);
            mLvLeftMenu.addHeaderView(inflater.inflate(R.layout.header_just_username, mLvLeftMenu, false));
            mLvLeftMenu.setAdapter(new MenuItemAdapter(this));
        }
    
        @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_nav_list_view, 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 == android.R.id.home)
            {
                mDrawerLayout.openDrawer(GravityCompat.START);
                return true;
            }
    
            return super.onOptionsItemSelected(item);
        }
    
    
    
    }
    

    直接看onCreate中的setUpDrawer(),能够看到我们首先去addHeadView。然后去setAdapter。

    那么核心代码就是我们的Adapter了~~

    (三)MenuItemAdapter

    
    
        public class LvMenuItem
        {
            public LvMenuItem(int icon, String name)
            {
                this.icon = icon;
                this.name = name;
    
                if (icon == NO_ICON && TextUtils.isEmpty(name))
                {
                    type = TYPE_SEPARATOR;
                } else if (icon == NO_ICON)
                {
                    type = TYPE_NO_ICON;
                } else
                {
                    type = TYPE_NORMAL;
                }
    
                if (type != TYPE_SEPARATOR && TextUtils.isEmpty(name))
                {
                    throw new IllegalArgumentException("you need set a name for a non-SEPARATOR item");
                }
    
                L.e(type + "");
    
    
            }
    
            public LvMenuItem(String name)
            {
                this(NO_ICON, name);
            }
    
            public LvMenuItem()
            {
                this(null);
            }
    
            private static final int NO_ICON = 0;
            public static final int TYPE_NORMAL = 0;
            public static final int TYPE_NO_ICON = 1;
            public static final int TYPE_SEPARATOR = 2;
    
            int type;
            String name;
            int icon;
    
        }
    
        public class MenuItemAdapter extends BaseAdapter
        {
            private final int mIconSize;
            private LayoutInflater mInflater;
            private Context mContext;
    
            public MenuItemAdapter(Context context)
            {
                mInflater = LayoutInflater.from(context);
                mContext = context;
    
                mIconSize = context.getResources().getDimensionPixelSize(R.dimen.drawer_icon_size);//24dp
            }
    
            private List<LvMenuItem> mItems = new ArrayList<LvMenuItem>(
                    Arrays.asList(
                            new LvMenuItem(R.drawable.ic_dashboard, "Home"),
                            new LvMenuItem(R.drawable.ic_event, "Messages"),
                            new LvMenuItem(R.drawable.ic_headset, "Friends"),
                            new LvMenuItem(R.drawable.ic_forum, "Discussion"),
                            new LvMenuItem(),
                            new LvMenuItem("Sub Items"),
                            new LvMenuItem(R.drawable.ic_dashboard, "Sub Item 1"),
                            new LvMenuItem(R.drawable.ic_forum, "Sub Item 2")
                    ));
    
    
            @Override
            public int getCount()
            {
                return mItems.size();
            }
    
    
            @Override
            public Object getItem(int position)
            {
                return mItems.get(position);
            }
    
    
            @Override
            public long getItemId(int position)
            {
                return position;
            }
    
            @Override
            public int getViewTypeCount()
            {
                return 3;
            }
    
            @Override
            public int getItemViewType(int position)
            {
                return mItems.get(position).type;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent)
            {
                LvMenuItem item = mItems.get(position);
                switch (item.type)
                {
                    case LvMenuItem.TYPE_NORMAL:
                        if (convertView == null)
                        {
                            convertView = mInflater.inflate(R.layout.design_drawer_item, parent,
                                    false);
                        }
                        TextView itemView = (TextView) convertView;
                        itemView.setText(item.name);
                        Drawable icon = mContext.getResources().getDrawable(item.icon);
                        setIconColor(icon);
                        if (icon != null)
                        {
                            icon.setBounds(0, 0, mIconSize, mIconSize);
                            TextViewCompat.setCompoundDrawablesRelative(itemView, icon, null, null, null);
                        }
    
                        break;
                    case LvMenuItem.TYPE_NO_ICON:
                        if (convertView == null)
                        {
                            convertView = mInflater.inflate(R.layout.design_drawer_item_subheader,
                                    parent, false);
                        }
                        TextView subHeader = (TextView) convertView;
                        subHeader.setText(item.name);
                        break;
                    case LvMenuItem.TYPE_SEPARATOR:
                        if (convertView == null)
                        {
                            convertView = mInflater.inflate(R.layout.design_drawer_item_separator,
                                    parent, false);
                        }
                        break;
                }
    
                return convertView;
            }
    
            public void setIconColor(Drawable icon)
            {
                int textColorSecondary = android.R.attr.textColorSecondary;
                TypedValue value = new TypedValue();
                if (!mContext.getTheme().resolveAttribute(textColorSecondary, value, true))
                {
                    return;
                }
                int baseColor = mContext.getResources().getColor(value.resourceId);
                icon.setColorFilter(baseColor, PorterDuff.Mode.MULTIPLY);
            }
        }

    首先我们的每一个Item相应于一个LvMenuItem。包括icon、name、type。能够看到我们的type分为3类。

    那么adapter中代码就非常easy了,多Item布局的写法。

    这样就完毕了,我们自己去书写NavigationView,是不是非常easy~~假设你的app须要相似效果,可是又与NavigationView的效果并不是一模一样。能够考虑依照上面的思路自己写一个。

    最后贴一下用到的Item的布局文件:

    • design_drawer_item_subheader.xml
    <?xml version="1.0" encoding="utf-8"?>
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="?

    attr/listPreferredItemHeightSmall" android:gravity="center_vertical|start" android:maxLines="1" android:paddingLeft="?attr/listPreferredItemPaddingLeft" android:paddingRight="?

    attr/listPreferredItemPaddingRight" android:textAppearance="?

    attr/textAppearanceListItem" android:textColor="?android:textColorSecondary"/>

    • design_drawer_item_separator.xml
    
    <?

    xml version="1.0" encoding="utf-8"?

    > <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="?android:attr/listDivider"/> </FrameLayout>

    • design_drawer_item,xml:
    <?

    xml version="1.0" encoding="utf-8"?

    > <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="?attr/listPreferredItemHeightSmall" android:paddingLeft="?attr/listPreferredItemPaddingLeft" android:paddingRight="?attr/listPreferredItemPaddingRight" android:drawablePadding="32dp" android:gravity="center_vertical|start" android:maxLines="1" android:textAppearance="?attr/textAppearanceListItem" android:textColor="?

    android:attr/textColorPrimary"/>

    ok。事实上上述ListView的写法也正是NavigationView的源代码实现~~item的布局文件直接从源代码中拖出来的,还是爽爽哒~

    源代码点击下载
    ~~hava a nice day ~~

    新浪微博

    微信公众号:hongyangAndroid
    (欢迎关注,第一时间推送博文信息)

    參考链接

  • 相关阅读:
    数据结构之 线性表 逆序简历链表
    数据结构之 线性表--顺序创建链表
    参观——校园招聘大会
    SDUT OJ 之 1571 《人品,有没有?》 字符串的处理问题
    青岛理工交流赛 H题 素数间隙
    青岛理工ACM交流赛 J题 数格子算面积
    STL版 括号匹配(感觉不如之前自己用数组模拟的跑的快)
    1076: [SCOI2008]奖励关( dp )
    BZOJ 1079: [SCOI2008]着色方案( dp )
    BZOJ 1984: 月下“毛景树”( 树链剖分 )
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5153985.html
Copyright © 2020-2023  润新知