Item布局layout_margin == 0
Item布局Layout_margin == 16dp
下面看代码的区别:
第一张图的代码, 也就是每一个list_item的布局文件(下同)如下:
<?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="50dp"> <TextViewandroid:id="@+id/list_item"android:layout_width="match_parent" android:layout_height="match_parent"android:gravity="center"android:textSize="20sp"android:textColor="#262526"android:background="#08da1d"/></LinearLayout>第二张图的代码:
<?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="50dp"android:layout_margin="16dp"> <TextViewandroid:id="@+id/list_item"android:layout_width="match_parent" android:layout_height="match_parent"android:gravity="center"android:textSize="20sp"android:textColor="#262526"android:background="#08da1d"/></LinearLayout>仔细看一下,它们的不同之处, 就是第二个图的代码中多了:
分隔线的位置图
我现在拿画横线来说,从上面这个图中,我们很容易就可以看到,我们画分隔线的位置,是在每一个Item的布局之间,注意:是布局之间。
好了,我们确定了画在哪里,那我们怎么确定画线的具体的坐标位置呢?也就是我们要确定:分隔线的left, top, right, Bottom. 在Adapter中,我们很容易通过parent(这个parent它其实就是我们能看到的部分)获取每一个childView:
(1)left:parent.getPaddingLeft()
(2)right: parent. getWidth()-parent.getPaddingRight();
(3)top : 就是红线的上面:我们通过ChildView.getBottom()来得到这个Item的底部的高度,也就是蓝线位置,蓝线和红线之间间距:就是这个Item布局文件的:layout_marginBottom, 然后top的位置就是两者之和。
(4)bttom: 就是top加上分隔线的高度:top+线高
通过上面的解析,你也许知道了加入分隔线的原理,不理解也没有关系,说也不是说得很清楚,下面直接上代码,通过代码来理解。
三. Talk is cheap, show you the code.
(1)首先,先来看主布局文件:activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="com.study.wnw.recyclerviewdivider.MainActivity"> <android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerview"android:layout_width="match_parent"android:layout_height="match_parent"></android.support.v7.widget.RecyclerView></android.support.design.widget.CoordinatorLayout>我在这里面仅仅加入了一个RecyclerView
<?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="50dp"android:layout_margin="16sp"> <TextViewandroid:id="@+id/list_item"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:textSize="20sp"android:textColor="#f7f4f7"android:background="#08da1d"/></LinearLayout>这也没有什么可讲的,就是在里面添加一个TextView用来显示文本
package com.study.wnw.recyclerviewdivider;import android.content.Context;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.TextView;import java.util.List;import java.util.concurrent.CopyOnWriteArrayList;/** * Created by wnw on 16-5-22. */public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { //定义一个集合,接收从Activity中传递过来的数据和上下文 private List<String> mList; private Context mContext; MyAdapter(Context context, List<String> list){this.mContext = context;this.mList = list; } //得到child的数量 @Override public int getItemCount() {return mList.size(); } //创建ChildView @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {View layout = LayoutInflater.from(mContext).inflate(R.layout.item_view, parent, false);return new MyHolder(layout); } //将数据绑定到每一个childView中 @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {if (holder instanceof MyHolder){ final String itemText = mList.get(position); ((MyHolder)holder).tv.setText(itemText);} } // 通过holder的方式来初始化每一个ChildView的内容 class MyHolder extends RecyclerView.ViewHolder{TextView tv;public MyHolder(View itemView) { super(itemView); tv = (TextView)itemView.findViewById(R.id.list_item);} }}好了,这里也没有什么好讲的,也不是我们这篇文章的重点,下面重点来了。
package com.study.wnw.recyclerviewdivider;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.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.Log;import android.view.View;/** * Created by wnw on 16-5-22. */public class MyDecoration extends RecyclerView.ItemDecoration{ private Context mContext; private Drawable mDivider; private int mOrientation; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; //我们通过获取系统属性中的listDivider来添加,在系统中的AppTheme中设置 public static final int[] ATRRS = new int[]{ android.R.attr.listDivider }; public MyDecoration(Context context, int orientation) {this.mContext = context;final TypedArray ta = context.obtainStyledAttributes(ATRRS);this.mDivider = ta.getDrawable(0);ta.recycle();setOrientation(orientation); } //设置屏幕的方向 public void setOrientation(int orientation){if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST){ throw new IllegalArgumentException("invalid orientation");}mOrientation = orientation; }@Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {if (mOrientation == HORIZONTAL_LIST){ drawVerticalLine(c, parent, state);}else { drawHorizontalLine(c, parent, state);} } //画横线, 这里的parent其实是显示在屏幕显示的这部分 public void drawHorizontalLine(Canvas c, RecyclerView parent, RecyclerView.State state){int left = parent.getPaddingLeft();int right = parent.getWidth() - parent.getPaddingRight();final int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++){ final View child = parent.getChildAt(i); //获得child的布局信息 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); //Log.d("wnw", left + " " + top + " "+right+" "+bottom+" "+i);} } //画竖线 public void drawVerticalLine(Canvas c, RecyclerView parent, RecyclerView.State state){int top = parent.getPaddingTop();int bottom = parent.getHeight() - parent.getPaddingBottom();final int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++){ final View child = parent.getChildAt(i);//获得child的布局信息 final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)child.getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c);} } //由于Divider也有长宽高,每一个Item需要向下或者向右偏移 @Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {if(mOrientation == HORIZONTAL_LIST){ //画横线,就是往下偏移一个分割线的高度 outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());}else { //画竖线,就是往右偏移一个分割线的宽度 outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);} }}从上面的代码中,我们还通过系统属性来适应屏幕的横屏和竖屏,然后确定画横的,还是竖的Divider,其实在里面我们做了三件事,第一件是:获取到系统中的listDivider, 我们就是通过它在主题中去设置的,下面第(6)小点看一下代码就知道了。第二件事:就是找到我们需要添加Divider的位置,从onDraw方法中去找到,并将Divider添加进去。第三个是:得到Item的偏移量。
package com.study.wnw.recyclerviewdivider;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity { //定义RecyclerView private RecyclerView mRecyclerView = null; //定义一个List集合,用于存放RecyclerView中的每一个数据 private List<String> mData = null; //定义一个Adapter private MyAdapter mAdapter;//定义一个LinearLayoutManager private LinearLayoutManager mLayoutManager; @Override protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//RecyclerView三步曲+LayoutManagerinitView();initData();mAdapter = new MyAdapter(this,mData);mRecyclerView.setLayoutManager(mLayoutManager);mRecyclerView.setAdapter(mAdapter); //这句就是添加我们自定义的分隔线mRecyclerView.addItemDecoration(new MyDecoration(this, MyDecoration.VERTICAL_LIST)); } //初始化View private void initView(){mLayoutManager = new LinearLayoutManager(this);mRecyclerView = (RecyclerView)findViewById(R.id.recyclerview); } //初始化加载到RecyclerView中的数据, 我这里只是给每一个Item添加了String类型的数据 private void initData(){mData = new ArrayList<String>();for (int i = 0; i < 20; i++){ mData.add("Item" + i);} }}(6)分隔线Divider的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="#7b7a7a"/> <size android:height="1dp"/></shape>我们在这里面,画了一个:rectangle, 给它填充颜色,还有高度,这样就搞定了,高度小,显示出来也是一条线:其实线的本质就是长方形。这里可以根据个人需要,画不同类型的divider
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="android:listDivider">@drawable/divider</item></style>这样,我们将系统的listDivider设置成我们自定义的divider. 还记得我们在MyDecoration中获取系统的listDivider这个属性吗,这样通过这个属性,我们就可以将我们的divider.xml文件和MyDecoration.java进行关联了。
竖屏效果图
横屏效果图
经过几个小时的写作,终于搞定了,虽然仅仅是一个添加分隔线的功能,但是还是想尽可能的通过自己的语言去理解,去认知它的原理,这样做起来就简单多了。一开始的时候,我夜不知道怎么去用,也参考了别人写的文章,特别是鸿洋大神的:Android RecyclerView 使用完全解析 体验艺术般的控件, 写得特别的棒,从中也学到了一些知识。
好了,这篇文章暂时写到这里了,简单的介绍了一些RecyclerView分隔线的原理和添加方法,希望大家能够多多交流,过几天我会继续写下一篇文章,RecyclerView系列之(3):为RecyclerView添加下拉刷新和上拉加载的功能。最后还是要感谢大家,感谢这个平台,能够让我们一起交流,一切学习。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。