天天看點

NavigationView自定義

做過Md風格app的朋友都應該用過Drawerlayout,而Drawerlayout的内容一般情況下是可以用support design包下的navigationview來實作。正如曾經的actionbar一樣,看似非常完美了,,但當你希望去修改每個icon顔色或者每個文字顔色的時候卻無法做到。正因如此本文主要介紹自定義navigationview的實作。還未使用過md風格控件的朋友可以先看看我另外一篇部落格http://blog.csdn.net/zly921112/article/details/50733435

先來看我們要實作的效果

NavigationView自定義

從navigationview源碼發現,整個清單其實就是用recyclerview實作,那麼同樣我們也依葫蘆畫瓢,直接撸碼

activity的布局檔案

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawerlayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

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

    </LinearLayout>


    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_drawer"
        android:layout_width="@dimen/drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="@color/white" />

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

這裡并沒有太多東西就是将drawerlayout的左側菜單設定為recyclerview

activity代碼

package com.zly.www.bzmh.activity;

import android.os.Bundle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;

import com.zly.www.bzmh.R;
import com.zly.www.bzmh.adapter.DrawerAdapter;
import com.zly.www.bzmh.base.BaseActivity;

import butterknife.Bind;
import butterknife.ButterKnife;

public class MainActivity extends BaseActivity {

    @Bind(R.id.drawerlayout)
    DrawerLayout drawerlayout;
    @Bind(R.id.rv_drawer)
    RecyclerView rvDrawer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        init();
    }

    private void init() {
        //抽屜初始化
        DrawerAdapter drawerAdapter = new DrawerAdapter();
        drawerAdapter.setOnItemClickListener(new MyOnItemClickListener());
        rvDrawer.setLayoutManager(new LinearLayoutManager(this));
        rvDrawer.setAdapter(drawerAdapter);
    }

    /**
     * drawer item 點選事件
     */
    public class MyOnItemClickListener implements DrawerAdapter.OnItemClickListener {

        @Override
        public void itemClick(DrawerAdapter.DrawerItemNormal drawerItemNormal) {
            switch (drawerItemNormal.titleRes) {
                case R.string.drawer_menu_home://首頁
                    break;
                case R.string.drawer_menu_rank://排行榜
                    break;
                case R.string.drawer_menu_column://欄目
                    break;
                case R.string.drawer_menu_search://搜尋
                    break;
                case R.string.drawer_menu_setting://設定
                    break;
                case R.string.drawer_menu_night://夜間模式
                    break;
                case R.string.drawer_menu_offline://離線
                    break;
            }
            drawerlayout.closeDrawer(GravityCompat.START);
        }
    }
}
           

activity同樣代碼也并不多,給左側的recyclerview設定adapter實作adapter中item點選接口

接下來就是adapter代碼了,前方高能,在這裡将會有比較多的代碼了

package com.zly.www.bzmh.adapter;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.facebook.drawee.view.SimpleDraweeView;
import com.zly.www.bzmh.R;

import java.util.Arrays;
import java.util.List;

/**
 * 抽屜adapter
 * Created by zly on 2016/3/30.
 */
public class DrawerAdapter extends RecyclerView.Adapter<DrawerAdapter.DrawerViewHolder> {

    private static final int TYPE_DIVIDER = ;
    private static final int TYPE_NORMAL = ;
    private static final int TYPE_HEADER = ;

    private List<DrawerItem> dataList = Arrays.asList(
            new DrawerItemHeader(),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_home, R.string.drawer_menu_home),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_rank, R.string.drawer_menu_rank),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_column, R.string.drawer_menu_column),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_search, R.string.drawer_menu_search),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_setting, R.string.drawer_menu_setting),
            new DrawerItemDivider(),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_night, R.string.drawer_menu_night),
            new DrawerItemNormal(R.mipmap.icon_drawerlayout_offline, R.string.drawer_menu_offline)
    );


    @Override
    public int getItemViewType(int position) {
        DrawerItem drawerItem = dataList.get(position);
        if (drawerItem instanceof DrawerItemDivider) {
            return TYPE_DIVIDER;
        } else if (drawerItem instanceof DrawerItemNormal) {
            return TYPE_NORMAL;
        }else if(drawerItem instanceof DrawerItemHeader){
            return TYPE_HEADER;
        }
        return super.getItemViewType(position);
    }

    @Override
    public int getItemCount() {
        return (dataList == null || dataList.size() == ) ?  : dataList.size();
    }

    @Override
    public DrawerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        DrawerViewHolder viewHolder = null;
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        switch (viewType) {
            case TYPE_DIVIDER:
                viewHolder = new DividerViewHolder(inflater.inflate(R.layout.item_drawer_divider, parent, false));
                break;
            case TYPE_HEADER:
                viewHolder = new HeaderViewHolder(inflater.inflate(R.layout.item_drawer_header, parent, false));
                break;
            case TYPE_NORMAL:
                viewHolder = new NormalViewHolder(inflater.inflate(R.layout.item_drawer_normal, parent, false));
                break;
        }
        return viewHolder;
    }

    @Override
    public void onBindViewHolder(DrawerViewHolder holder, int position) {
        final DrawerItem item = dataList.get(position);
        if (holder instanceof NormalViewHolder) {
            NormalViewHolder normalViewHolder = (NormalViewHolder) holder;
            final DrawerItemNormal itemNormal = (DrawerItemNormal) item;
            normalViewHolder.iv.setBackgroundResource(itemNormal.iconRes);
            normalViewHolder.tv.setText(itemNormal.titleRes);

            normalViewHolder.view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(listener != null){
                        listener.itemClick(itemNormal);

                    }
                }
            });
        }else if(holder instanceof HeaderViewHolder){
            HeaderViewHolder headerViewHolder = (HeaderViewHolder) holder;
        }

    }

    public OnItemClickListener listener;

    public void setOnItemClickListener(OnItemClickListener listener){
        this.listener = listener;
    }

    public interface OnItemClickListener{
        void itemClick(DrawerItemNormal drawerItemNormal);
    }




    //-------------------------item資料模型------------------------------
    // drawerlayout item統一的資料模型
    public interface DrawerItem {
    }


    //有圖檔和文字的item
    public class DrawerItemNormal implements DrawerItem {
        public int iconRes;
        public int titleRes;

        public DrawerItemNormal(int iconRes, int titleRes) {
            this.iconRes = iconRes;
            this.titleRes = titleRes;
        }

    }

    //分割線item
    public class DrawerItemDivider implements DrawerItem {
        public DrawerItemDivider() {
        }
    }

    //頭部item
    public class DrawerItemHeader implements DrawerItem{
        public DrawerItemHeader() {
        }
    }



    //----------------------------------ViewHolder資料模型---------------------------
    //抽屜ViewHolder模型
    public class DrawerViewHolder extends RecyclerView.ViewHolder {

        public DrawerViewHolder(View itemView) {
            super(itemView);
        }
    }

    //有圖示有文字ViewHolder
    public class NormalViewHolder extends DrawerViewHolder {
        public View view;
        public TextView tv;
        public ImageView iv;

        public NormalViewHolder(View itemView) {
            super(itemView);
            view = itemView;
            tv = (TextView) itemView.findViewById(R.id.tv);
            iv = (ImageView) itemView.findViewById(R.id.iv);
        }
    }

    //分割線ViewHolder
    public class DividerViewHolder extends DrawerViewHolder {

        public DividerViewHolder(View itemView) {
            super(itemView);
        }
    }

    //頭部ViewHolder
    public class HeaderViewHolder extends DrawerViewHolder {

        private SimpleDraweeView sdv_icon;
        private TextView tv_login;

        public HeaderViewHolder(View itemView) {
            super(itemView);
            sdv_icon = (SimpleDraweeView) itemView.findViewById(R.id.sdv_icon);
            tv_login = (TextView) itemView.findViewById(R.id.tv_login);
        }
    }
}
           

看着代碼很多其實内容相對簡單,這裡也就是根據資料結構來加載對應的布局.并将條目點選事件暴露出來.這裡為了友善我把資料直接寫在了adapter内部,也可以在activity中直接從adapter構造方法傳入.

分割線布局item_drawer_divider.xml

<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="1dp"
    android:background="?android:attr/listDivider"/>
           

頭部布局item_drawer_header.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:fresco="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="@dimen/drawer_header_height"
    android:background="?attr/colorPrimary"
    android:orientation="vertical">

    <com.facebook.drawee.view.SimpleDraweeView
        android:id="@+id/sdv_icon"
        android:layout_width="@dimen/drawer_header_icon_size"
        android:layout_height="@dimen/drawer_header_icon_size"
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        fresco:placeholderImage="@mipmap/icon_bg"
        fresco:roundAsCircle="true"/>

    <TextView
        android:id="@+id/tv_login"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/sdv_icon"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:text="登入"
        android:textColor="@color/white"
        android:textSize="@dimen/text_micro" />
</RelativeLayout>
           

清單布局item_drawer_normal.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="@dimen/drawer_item_height"
    android:gravity="center_vertical"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="@dimen/drawer_item_icon_size"
        android:layout_height="@dimen/drawer_item_icon_size"
        android:layout_marginLeft="@dimen/drawer_item_icon_leftmargin" />

    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/drawer_item_text_leftmargin"
        android:textColor="@color/black"
        android:textSize="@dimen/text_small" />
</LinearLayout>
           

資源檔案

strings.xml

<resources>
    <!-- drawer_menu_text-->
    <string name="drawer_menu_home">首頁</string>
    <string name="drawer_menu_rank">排行榜</string>
    <string name="drawer_menu_column">欄目</string>
    <string name="drawer_menu_search">搜尋</string>
    <string name="drawer_menu_setting">設定</string>
    <string name="drawer_menu_night">夜間模式</string>
    <string name="drawer_menu_offline">離線</string>
</resources>
           

dimens.xml

<resources>
    <!-- drawerlayoutsize-->
    <dimen name="drawer_width">260dp</dimen>
    <dimen name="drawer_header_height">140dp</dimen>
    <dimen name="drawer_header_icon_size">50dp</dimen>
    <dimen name="drawer_item_icon_size">14dp</dimen>
    <dimen name="drawer_item_height">44dp</dimen>
    <dimen name="drawer_item_icon_leftmargin">14dp</dimen>
    <dimen name="drawer_item_text_leftmargin">38dp</dimen>


    <!-- 字型大小 -->
    <dimen name="text_micro">12sp</dimen>
    <dimen name="text_small">14sp</dimen>
    <dimen name="text_medium">18sp</dimen>
    <dimen name="text_large">20sp</dimen>
</resources>
           

到此已經可以實作navigationview一樣的效果了,但是到此還有一點小小的瑕疵就是條目點選的波紋效果

可以通過如下代碼設定波紋的背景:

A: android:background=”?android:attr/selectableItemBackground”波紋有邊界

B: android:background=”?android:attr/selectableItemBackgroundBorderless”波紋超出邊界

效果A:

NavigationView自定義

效果B:

NavigationView自定義

顯然隻需要給清單布局加上android:background=”?android:attr/selectableItemBackground”即可完成點選波紋效果

而這個波紋的顔色我們可以通過修改styles.xml中colorControlHighlight(android:colorControlHighlight:設定波紋顔色)屬性來調節動畫顔色,進而可以适應不同的主題,但有一點要注意這個波紋效果隻能在5.0以上有效,5.0以下就跟普通選擇器一樣.