笔记:MaterialDesign(一)--控/组件简单使用

2018-05-09  本文已影响214人  RoJacKing

忘了贴图 copy代码运行看效果

一、TabLayout+ViewPager+Fragment

1.1、MainActivity.java中使用
public class MainActivity extends AppCompatActivity {

    private TabLayout mTabLayout;
    private ViewPager mViewPager;
    private LinearLayout mLinearLayout;

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

        mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
        mViewPager = (ViewPager) findViewById(R.id.viewPager);
        /**
         * 将TabLayout与ViewPager结合
         *
         */
        //步骤一:给VIewPager设置Adapter(FragmentPagerAdapter)
        MyViewPagerAdapter adapter = new MyViewPagerAdapter(getSupportFragmentManager());
        mViewPager.setAdapter(adapter);

        /**
         * 步骤二(到了步骤二可以看效果了,后面步骤是设置indicator属性等代码)
         *
         * 很牛逼的一个方法
         *
         * 关联TabLayout与ViewPager,互相绑定,且适配器必须重写getPageTitle()方法
         *
         * 这个方法三个作用
         *                               1、从ViewPager中获取TabLayout的Title----getPageTitle()
         *                               2、ViewPager滑动时,设置TabLayout的Title和indicator
         *                               3、点击TabLayout时,ViewPager相应变化
         */
        mTabLayout.setupWithViewPager(mViewPager);

        //步骤三   设置分割线:参考https://www.jianshu.com/p/bbefb97cccdd
        mLinearLayout = (LinearLayout) mTabLayout.getChildAt(0);
        // 在所有子控件的中间显示分割线(还可 只显示顶部、尾部和不显示分割线)
        mLinearLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
        // 设置分割线的距离本身(LinearLayout)的内间距
        mLinearLayout.setDividerPadding(50);
        // 设置分割线的样式
        mLinearLayout.setDividerDrawable(ContextCompat.getDrawable(this, R.drawable.divider_vertical));
        mLinearLayout.setBackgroundColor(getResources().getColor(R.color.colorPrimaryDark));


        //步骤四   设置指示器的长度(本来是不可设置的),这里是通过Tab外间距的方式
        // 自定义指示器(Indicator)的“长度”的两种方法,会有跳动的bug情况未解决,不推荐使用只做为一种示例
        // 方法一:反射
//                setIndicator(mTabLayout,10,10);
        // 方法二:查找子控件
        int left = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, Resources.getSystem().getDisplayMetrics());
        int right = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, Resources.getSystem().getDisplayMetrics());
        for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
            View tabView = mLinearLayout.getChildAt(i);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
            params.leftMargin = left;
            params.rightMargin = right;
            tabView.setLayoutParams(params);
        }
    }


    public void setIndicator(TabLayout tabs, int leftDip, int rightDip) {
        Class<?> tabLayout = tabs.getClass();
        Field tabStrip = null;//java.lang.reflect.Field
        try {
            tabStrip = tabLayout.getDeclaredField("mTabStrip");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        tabStrip.setAccessible(true);
        LinearLayout llTab = null;
        try {
            llTab = (LinearLayout) tabStrip.get(tabs);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        int left = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, leftDip, Resources.getSystem().getDisplayMetrics());
        int right = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rightDip, Resources.getSystem().getDisplayMetrics());

        for (int i = 0; i < llTab.getChildCount(); i++) {
            View child = llTab.getChildAt(i);
            child.setPadding(0, 0, 0, 0);
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.MATCH_PARENT, 1);
            params.leftMargin = left;
            params.rightMargin = right;
            child.setLayoutParams(params);
            child.invalidate();
        }
    }


    //步骤一(1)
    private class MyViewPagerAdapter extends FragmentPagerAdapter {

        //步骤一(1)、②  数据
        private final String[] title = new String[]{
                "推荐", "热点", "视频", "图片", "新闻",
                "汽车", "科技","财经", "游戏", "广州","旅游"};


        public MyViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            //步骤一(1)、③  实例化fragment

            Fragment fragment = new TextFragment();
            //给fragment传数据
            Bundle bundle = new Bundle();
            bundle.putString("title", title[position]);
            fragment.setArguments(bundle);
            return fragment;
        }

        @Override
        public int getCount() {
            return title.length;
        }

        //步骤一(1)、①  实例化fragment
        @Override
        public CharSequence getPageTitle(int position) {
            return title[position];
        }
    }
}
1.2、在activity_main.xml中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">

    <android.support.design.widget.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabBackground="@color/colorPrimaryDark"
        app:tabMode="scrollable"
        app:tabSelectedTextColor="@android:color/white"
        app:tabTextColor="@android:color/darker_gray"/>

    <!--
        app:tabBackground="@color/colorPrimaryDark"整个tablayout的背景颜色
        app:tabMode="scrollable"超出屏幕tablayout可滚动
        app:tabSelectedTextColor="@android:color/white"被选中的颜色
        app:tabTextColor="@android:color/darker_gray"非选中的颜色
     -->

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>

二、ListPopupWindow

2.1、在MainActivity.java中
public class MainActivity extends AppCompatActivity {

    private ListPopupWindow mListPopupWindow;
    private ArrayAdapter<String> mAdapter;
    private String[] mItemArr;

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

        mItemArr = new String[]{"test 1", "test 2", "test 3", "test 4", "test 5", "test 6", "test 7", "test 8"};
        mAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, mItemArr);

    }

    public void showPopupWindow(View view){
        if (mListPopupWindow == null)
            mListPopupWindow = new ListPopupWindow(this);
        //应该是 设置 ListPopupWindow 的数据适配器
        mListPopupWindow.setAdapter(mAdapter);
        //应该是 设置 ListPopupWindow 的显示位置(在指定控件下方)
        mListPopupWindow.setAnchorView(view);
        //应该是 设置上下边距的距离
        mListPopupWindow.setVerticalOffset(10);
        //应该是 设置 ListPopupWindow 的宽度
        mListPopupWindow.setWidth(300);
        //应该是 设置 ListPopupWindow 的高度
        mListPopupWindow.setHeight(600);
        //应该是 设置 ListPopupWindow 的条目点击事件(必须在show方法前设置,否则无效)
        mListPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(getApplicationContext(), mItemArr[position], Toast.LENGTH_SHORT).show();
                mListPopupWindow.dismiss();
            }
        });
        mListPopupWindow.show();
    }
2.2、在 activity_main.xml 中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="showPopupWindow"
        android:text="listPoppupWindow测试"/>

</LinearLayout>

三、PopupMenu的简单使用

3.1、在MainActivity.java中
 public void showPopupMenu(View view) throws NoSuchFieldException, IllegalAccessException {
        PopupMenu popupMenu = new PopupMenu(this, view);
        //设置 PopupMenu 的显示菜单项
        popupMenu.inflate(R.menu.main);
        // popupMenu.getMenuInflater().inflate(R.menu.main, popupMenu.getMenu());//上一行与这一行效果一样
        //默认 PopupMenu 不显示条目icon,可以通过反射来强制使其显示icon
        Field field = popupMenu.getClass().getDeclaredField("mPopup");
        field.setAccessible(true);
        MenuPopupHelper mHelper = (MenuPopupHelper) field.get(popupMenu);
        mHelper.setForceShowIcon(true);
        //设置 PopupMenu 的条目点击事件(点击后会自动dismiss)
        popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem item) {
                Toast.makeText(getApplicationContext(), item.getTitle(), Toast.LENGTH_SHORT).show();
                return false;
            }
        });
        //显示 PopupMenu
        popupMenu.show();
    }
3.2、在 activity_main.xml 中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="showPopupMenu"
        android:text="PopupMenu测试"/>

</LinearLayout>
3.3、main.xml 资源(res/menu/main.xml)
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:icon="@mipmap/ic_launcher"
        android:orderInCategory="100"
        android:title="test 1"
        app:showAsAction="withText"/>
    <item
        android:icon="@mipmap/ic_launcher"
        android:orderInCategory="101"
        android:title="test 2"
        app:showAsAction="withText"
        />
    <item
        android:icon="@mipmap/ic_launcher"
        android:orderInCategory="103"
        android:title="test 3"
        app:showAsAction="withText"
        />
</menu>

四、LinearLayoutCompat的简单使用

4.1、在MainActivity.java中

public class MainActivity extends AppCompatActivity {

    private LinearLayoutCompat linearLayoutCompat;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        linearLayoutCompat = (LinearLayoutCompat) findViewById(R.id.linearLayoutCompat);
    }

    //布局的前面一个分割线
    public void beginning(View view) {
        linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_BEGINNING);
    }
    //布局的除了前面和后面没有分割线,中间控件之间都有分割线
    public void middle(View view) {
        linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_MIDDLE);
    }
    //布局的尾部一个分割线
    public void end(View view) {
        linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_END);
    }
    //布局的除了尾部没有分割线,其他有(前面和中间)
    public void beginning_middle(View view) {
        linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_BEGINNING | LinearLayoutCompat.SHOW_DIVIDER_MIDDLE);

    }
    //布局的除了前面没有分割线,其他有(中间和后面)
    public void end_middle(View view) {
        linearLayoutCompat.setShowDividers(LinearLayoutCompat.SHOW_DIVIDER_MIDDLE | LinearLayoutCompat.SHOW_DIVIDER_END);
    }

}
4.2、在 activity_main.xml 中
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="beginning"
            android:text="beginning"
            android:textAllCaps="false"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="middle"
            android:text="middle"
            android:textAllCaps="false"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="end"
            android:text="end"
            android:textAllCaps="false"/>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:orientation="horizontal">

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="beginning_middle"
            android:text="beginning|middle"
            android:textAllCaps="false"/>

        <Button
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="end_middle"
            android:text="end|middle"
            android:textAllCaps="false"/>


    </LinearLayout>

    <android.support.v7.widget.LinearLayoutCompat
        android:id="@+id/linearLayoutCompat"
        android:layout_marginTop="10dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:orientation="vertical"
        app:divider="@drawable/line"
        app:showDividers="beginning">

        <android.support.v7.widget.AppCompatEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="AppCompatEditText"/>

        <android.support.v7.widget.AppCompatTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="AppCompatTextView"/>

        <android.support.v7.widget.AppCompatButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="AppCompatButton"/>

        <android.support.v7.widget.AppCompatCheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:text="这个AppCompatCheckBox\n下面的一排五星是AppCompatRatingBar控件"/>

        <android.support.v7.widget.AppCompatRatingBar
            android:layout_marginTop="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    </android.support.v7.widget.LinearLayoutCompat>
</LinearLayout>

五、RecyclerView.ItemDecoration 条目item装饰 的简单使用

①、水平/垂直分割线
②、网格布局分割线
③、侧边字母提示样式
④、悬浮头布局样式

5.1、水平/垂直 分割线 装饰

5.1.1、在MainActivity.java中
public class MainActivity extends AppCompatActivity {

    private List<String> mData = new ArrayList<>();
    private RecyclerView mRv;
    private MyAdapter mMyAdapter;

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

        mRv = (RecyclerView) findViewById(R.id.rv);

        initDecoration();
        initData();
        initRecyclerView();

    }

    //初始化修饰布局(分割线)
    private void initDecoration() {
        MyDecorationOne decorationOne = new MyDecorationOne(this, LinearLayoutManager.VERTICAL);
        mRv.addItemDecoration(decorationOne);
    }

    //初始化数据
    private void initData() {
        for (int i = 0; i < 100; i++) {
            mData.add("item " + i);
        }
    }

    //初始化recyclerview,关联adapter
    private void initRecyclerView() {
        mMyAdapter = new MyAdapter(mData);
        mRv.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
        mRv.setAdapter(mMyAdapter);
    }

}
5.1.2、在activity_main.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:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
5.1.3、自定义装饰 MyDecorationOne.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by ${chenyuexueer} on 2018/5/9.
 * <p>
 * 说明:自定义recyclerview的自定义条目装饰(分割线,当然它不仅仅可以作为分割线)
 *
 * 1、继承RecyclerView.ItemDecoration,
 * 重写 public void onDraw()和 public void getItemOffsets()方法(并不是必须,可不要)
 *
 * 2、构造方法,初始化属性等
 *
 * 3、设计绘图方法
 */

public class MyDecorationOne extends RecyclerView.ItemDecoration {

    int orientation = RecyclerView.VERTICAL;//默认垂直
    private final Drawable mDivider;

    public MyDecorationOne(Context context, int orientation) {
        this.orientation = orientation;//初始化recyclerview布局方向,activity传过来的recyclerview的布局方向
        int[] attrs = new int[]{android.R.attr.listDivider};//系统提供的属性
        TypedArray a = context.obtainStyledAttributes(attrs);//属性组
        mDivider = a.getDrawable(0);//取组中第一个
        a.recycle();//回收
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);

        int childCount = parent.getChildCount();//recyclerview的子item的条数

        if (orientation == RecyclerView.HORIZONTAL) {//activity那边设置是水平布局,则绘制一个个垂直()装饰
            drawVertical(c, parent,childCount);
        } else if (orientation == RecyclerView.VERTICAL) {//activity那边设置是水平布局,则绘制一个个垂直装饰
            drawHorizontal(c, parent,childCount);
        }
    }

    //绘制垂直装饰
    private void drawVertical(Canvas c, RecyclerView parent,  int childCount) {

        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);//第i条item的view对象
            //第i条item的view对象的布局参数
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            //计算装饰(分割线)的绘制参数(边距)
            int left = child.getRight() + params.rightMargin;
            int top = child.getTop() - params.topMargin;
            int right = left + mDivider.getIntrinsicWidth();
            int bottom = child.getBottom() + params.bottomMargin;
            //设置装饰(分割线)边距
            mDivider.setBounds(left, top, right, bottom);
            //开始绘制
            mDivider.draw(c);
        }
    }

    //绘制水平装饰
    private void drawHorizontal(Canvas c, RecyclerView parent,  int childCount) {

        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int left = child.getLeft() - params.leftMargin;
            int top = child.getBottom() + params.bottomMargin;
            int right = child.getRight() + params.rightMargin;
            int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    /**
     * 设置条目周边的偏移量(即偏移分割线的大小距离)
     */
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        if (orientation == RecyclerView.HORIZONTAL) {
            //画垂直线
            outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
        } else if (orientation == RecyclerView.VERTICAL) {
            //画水平线
            outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
        }
    }
5.1.4、MyAdapter.java
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.List;

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

    private List<String> mData;

    public MyAdapter(List<String> data) {
        mData = data;
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = View.inflate(parent.getContext(), android.R.layout.simple_list_item_1, null);
        itemView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        return new MyViewHolder(itemView);
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.mTv.setText(mData.get(position));
    }

    @Override
    public int getItemCount() {
        return mData.size();
    }

    class MyViewHolder extends RecyclerView.ViewHolder {

        TextView mTv;

        public MyViewHolder(View itemView) {
            super(itemView);
            mTv = (TextView) itemView.findViewById(android.R.id.text1);
        }
    }

}

5.2、网格分割 装饰

5.2.1、MainActivity.java
public class MainActivity extends AppCompatActivity {

    private List<String> mData = new ArrayList<>();
    private RecyclerView mRv;
    private MyAdapter mMyAdapter;

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

        mRv = (RecyclerView) findViewById(R.id.rv);

        initDecoration();
        initData();
        initRecyclerView();

    }

    //初始化修饰布局(分割线)
    private void initDecoration() {
        MyDecorationTwo decorationTwo = new MyDecorationTwo(this);
        mRv.addItemDecoration(decorationTwo);
    }

    //初始化数据
    private void initData() {
        for (int i = 0; i < 100; i++) {
            mData.add("item " + i);
        }
    }

    //初始化recyclerview,关联adapter,这里使用GridLayoutManager表格布局
    private void initRecyclerView() {
        mMyAdapter = new MyAdapter(mData);
        mRv.setLayoutManager(new GridLayoutManager(this, 4));
        mRv.setAdapter(mMyAdapter);
    }

}
5.2.2、activity_main.xml

具体代码----同上(5.1.2、activity_main.xml)

5.2.3、 MyAdapter.java

具体代码----同上(5.1.4、MyAdapter.java)

5.2.4、自定义装饰 MyDecorationTwo.java
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;

/**
 * Created by ${chenyuexueer} on 2018/5/9.
 * <p>
 * 说明:自定义recyclerview的自定义条目装饰(网格分割)
 *
 * 1、构造方法,初始化属性等
 *
 * 2、继承RecyclerView.ItemDecoration,
 * 重写 public void onDraw()和 public void getItemOffsets()方法
 * public void getItemOffsets()方法并不是必须,可不用(没有节点),可以注释掉这个方法看效果
 *
 * 3、设计绘图方法
 */

public class MyDecorationTwo extends RecyclerView.ItemDecoration {

    private final Drawable mDivider;

    public MyDecorationTwo(Context context) {//构造方法初始化数据

        //与MyDecorationOne相比,这里是自定义的资源文件,MyDecorationOne是系统提供的资源文件
        mDivider = context.getResources().getDrawable(R.drawable.divider);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);

        int childCount = parent.getChildCount();//recyclerview的子item的条数

        //水平垂直都要绘制分割线,这样才能形成网格
        drawVertical(c, parent,childCount);
        drawHorizontal(c, parent,childCount);
    }

    //绘制垂直装饰
    private void drawVertical(Canvas c, RecyclerView parent, int childCount) {

        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);//第i条item的view对象
            //第i条item的view对象的布局参数
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            //计算装饰(分割线)的绘制参数(边距)
            int left = child.getRight() + params.rightMargin;
            int top = child.getTop() - params.topMargin;
            int right = left + mDivider.getIntrinsicWidth();
            int bottom = child.getBottom() + params.bottomMargin;
            //设置装饰(分割线)边距
            mDivider.setBounds(left, top, right, bottom);
            //开始绘制
            mDivider.draw(c);
        }
    }

    //绘制水平装饰
    private void drawHorizontal(Canvas c, RecyclerView parent, int childCount) {

        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            int left = child.getLeft() - params.leftMargin;
            int top = child.getBottom() + params.bottomMargin;
            int right = child.getRight() + params.rightMargin;
            int bottom = top + mDivider.getIntrinsicHeight();
            mDivider.setBounds(left, top, right, bottom);
            mDivider.draw(c);
        }
    }

    /**
     * 设置条目右下边的偏移量(效果:右下边有一个空白的小正方形节点)
     */
    @Override
    public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
        super.getItemOffsets(outRect, itemPosition, parent);

        //getIntrinsicWidth()/getIntrinsicHeight()与getWidth()/getHeight()区别具体请自行百度谷歌
        int right = mDivider.getIntrinsicWidth();
        int bottom = mDivider.getIntrinsicHeight();

        //第itemPosition个条目item的最后一列,即正方形的下边,则不需要绘制右边
        if (isLastSpan(itemPosition, parent)) {
            right = 0;
        }

        //第itemPosition个条目item的最后一行,即正方形的右边,则不需要绘制底部
        if (isLastRow(itemPosition, parent)) {
            bottom = 0;
        }
        outRect.set(0, 0, right, bottom);
    }

    public boolean isLastRow(int itemPosition, RecyclerView parent) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
            int itemCount = parent.getAdapter().getItemCount();
            if ((itemCount - itemPosition - 1) < spanCount)//则不需要底部
                return true;
        }
        return false;
    }

    public boolean isLastSpan(int itemPosition, RecyclerView parent) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            int spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
            if ((itemPosition + 1) % spanCount == 0)//则不需要绘制右边
                return true;
        }
        return false;
    }
}
5.2.4、divider.xml 资源文件 res/drawable/divider.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">

    <solid android:color="#f00"/>
    <size
        android:width="2dp"
        android:height="2dp"/>

</shape>

5.3、侧边字母提示 装饰

需要依赖 拼音工具包
sourceforge 开源项目jar包
Github 依赖

5.3.1、MainActivity.java
public class MainActivity extends AppCompatActivity {

    private List<String> mData = new ArrayList<>();
    private RecyclerView mRv;
    private MyAdapter mMyAdapter;

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

        mRv = (RecyclerView) findViewById(R.id.rv);

        initData();
        initDecoration();
        initRecyclerView();

    }

    //初始化修饰布局(首字母提示)
    private void initDecoration() {
        MyDecorationThree decorationThree = new MyDecorationThree(this, mData);
        mRv.addItemDecoration(decorationThree);
    }

    //初始化数据
    private void initData() {
        mData = Arrays.asList(Cheeses.NAMES);
        //系统方法     排序
        Collections.sort(mData, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return PinyinUtils.getPinyin(o1).compareTo(PinyinUtils.getPinyin(o2));
            }
        });
    }

    //初始化recyclerview,关联adapter
    private void initRecyclerView() {
        mMyAdapter = new MyAdapter(mData);
        mRv.setLayoutManager(new LinearLayoutManager(this));
        mRv.setAdapter(mMyAdapter);
    }

}
5.3.2、拼音工具 PinyinUtils.java
/**
 * Created by ${chenyuexueer} 
 * 
 * 说明:拼音工具(需要依赖或者导入pinyin4j-2.5.0.jar)
 */

public class PinyinUtils {

    /**
     * 根据传入的字符串(包含汉字),得到拼音
     * 如:
     *
     * 好学 -> HAOXUE
     * 好 学*& -> HAOXUE
     * 好学y2 -> HAOXUE
     *
     * @param str 字符串
     * @return
     */
    public static String getPinyin(String str) {

        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);

        StringBuilder sb = new StringBuilder();

        char[] charArray = str.toCharArray();
        for (int i = 0; i < charArray.length; i++) {
            char c = charArray[i];
            // 如果是空格, 跳过
            if (Character.isWhitespace(c)) {
                continue;
            }
            if (c >= -127 && c < 128 || !(c >= 0x4E00 && c <= 0x9FA5)) {
                // 满足条件 ,则肯定不是汉字
                sb.append(c);
            } else {
                String s = "";
                try {
                    // 通过char得到拼音集合. 单 -> dan, shan
                    s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0];
                    sb.append(s);
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                    sb.append(s);
                }
            }
        }

        return sb.toString();
    }

}
5.3.3、自定义修饰类 MyDecorationThree .java
/**
 * Created by ${chenyuexueer} 
 * <p>
 * 说明:
 */

public class MyDecorationThree extends RecyclerView.ItemDecoration {

    Context mContext;
    List<String> mData;
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);//画笔

    public MyDecorationThree(Context context, List<String> data) {
        mContext = context;
        mData = data;
        //画笔字体大小与颜色
        paint.setTextSize(sp2px(16));
        paint.setColor(Color.RED);
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        super.onDraw(c, parent, state);
        drawLetterToItemLeft(c, parent);
    }

    /**
     * 绘制方法
     * @param c     画布
     * @param parent    RecyclerView
     */
    private void drawLetterToItemLeft(Canvas c, RecyclerView parent) {

        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (!(layoutManager instanceof LinearLayoutManager)){
            return;
        }

        int childCount = parent.getChildCount();

        for (int i = 0; i < childCount; i++) {
            int position = ((LinearLayoutManager) layoutManager).findFirstVisibleItemPosition() + i;
            View child = parent.getChildAt(i);
            RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
            float left = 0;
            float top = child.getTop() - params.topMargin;
            float right = child.getLeft() - params.leftMargin;
            float bottom = child.getBottom() + params.bottomMargin;
            float width = right - left;
            float height = bottom - (bottom - top) / 2;
            //当前名字拼音的第一个字母
            String letter = PinyinUtils.getPinyin(mData.get(position)).charAt(0) + "";
            if (position == 0) {
                drawLetter(letter, width, height, c, parent);
            } else {
                String preLetter = PinyinUtils.getPinyin(mData.get(position - 1)).charAt(0) + "";
                if (!letter.equalsIgnoreCase(preLetter)) {
                    drawLetter(letter, width, height, c, parent);
                }
            }
        }
    }

    private void drawLetter(String letter, float width, float height, Canvas c, RecyclerView parent) {
        float fontLength = getFontLength(paint, letter);
        float fontHeight = getFontHeight(paint);
        float tx = (width - fontLength) / 2;
        float ty = height - fontHeight / 2 + getFontLeading(paint);
        c.drawText(letter, tx, ty, paint);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        super.getItemOffsets(outRect, view, parent, state);
        outRect.set(dip2px(40), 0, 0, 0);
    }

    private int dip2px(int dip) {
        float density = mContext.getResources().getDisplayMetrics().density;
        int px = (int) (dip * density + 0.5f);
        return px;
    }

    public int sp2px(int sp) {
        return (int) (TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, mContext.getResources().getDisplayMetrics()) + 0.5f);
    }

    /**
     * 返回指定笔和指定字符串的长度
     */
    private float getFontLength(Paint paint, String str) {
        return paint.measureText(str);
    }
    /**
     * 返回指定笔的文字高度
     */
    private float getFontHeight(Paint paint) {
        Paint.FontMetrics fm = paint.getFontMetrics();
        return fm.descent - fm.ascent;
    }
    /**
     * 返回指定笔离文字顶部的基准距离
     */
    private float getFontLeading(Paint paint) {
        Paint.FontMetrics fm = paint.getFontMetrics();
        return fm.leading - fm.ascent;
    }
}
5.3.4、名字数组数据类Cheeses.java

/**
 * Created by ${chenyuexueer}
 * 说明:姓名数据
 */

public class Cheeses {

    public static final String[] NAMES = new String[] { "宋江", "卢俊义", "吴用",
            "公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深",
            "武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘",
            "雷横", "李俊", "阮小二", "张横", "阮小五", " 张顺", "阮小七", "杨雄", "石秀", "解珍",
            " 解宝", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷珪",
            "魏定国", "萧让", "裴宣", "欧鹏", "邓飞", " 燕顺", "杨林", "凌振", "蒋敬", "吕方",
            "郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充",
            "李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿",
            "陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "施恩",
            "周通", "李忠", "杜兴", "汤隆", "邹渊", "邹润", "朱富", "朱贵", "蔡福", "蔡庆", "李立",
            "李云", "焦挺", "石勇", "孙新", "顾大嫂", "张青", "孙二娘", " 王定六", "郁保四", "白胜",
            "时迁", "段景柱" };

}
5.3.5、activity_main.xml

具体代码----同上(5.1.2、activity_main.xml)

5.3.6、 MyAdapter.java

具体代码----同上(5.1.4、MyAdapter.java)

5.4、悬浮头布局(使用ItemDecoration)

懒得写,将就着看这个吧,这个结合几个效果一起使用《Android二级联动》

MaterialDesign笔记(二)--控/组件简单使用
参考自

上一篇下一篇

猜你喜欢

热点阅读