ViewDragHelper一般用在一个自定义ViewGroup的内部,用来处理子View的拖拽和滑动处理
水平滑动
下面我们创建一个SimpleLayout继承自LinearLayout
public class SimpleLayout extends LinearLayout {
private static final String TAG = "SimpleLayoutTest";
private ViewDragHelper mViewDragHelper;
public SimpleLayout(Context context) {
this(context, null);
}
public SimpleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SimpleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mViewDragHelper = ViewDragHelper.create(this, 1.0f,new ViewDragCallback());
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
// 如果当前事件ACTION_CANCEL或者ACTION_UP,停止一切拖拽处理
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mViewDragHelper.cancel();
return false;
}
// 必须调用mViewDragHelper.shouldInterceptTouchEvent(ev),让事件拦截在mViewDragHelper自己处理
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// 调用mViewDragHelper.processTouchEvent(ev); 将当前事件交给mViewDragHelper处理
mViewDragHelper.processTouchEvent(ev);
return true;
}
class ViewDragCallback extends ViewDragHelper.Callback {
/**
* tryCaptureView 用来指定我们的Layout中哪一个view可以被处理拖动
* 返回true表示所有,也可以返回指定的view,比如:
* child1 || child2 表示处理child1和child2的拖拽
* @param child
* @param pointerId
* @return
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
/**
* 水平拖拽当前child
* @param child
* @param left 当前child距离当前ViewGroup左边的位置
* @param dx 每次移动当前child的距离
* @return
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
Log.d(TAG,"left is :"+left+" dx is :"+dx);
return left;
}
}
}
可以看到ViewDragHelper类似于GestureDetector的使用,即都是将当前的事件拦截和处理交给ViewDragHelper来处理,下面简单总结下使用方法
- 创建自定义ViewGroup,在构造方法初始化ViewDragHelper
mViewDragHelper = ViewDragHelper.create(this, 1.0f,new ViewDragCallback());
// 第一个参数this表示作用于当前自定义ViewGroup
// 第二个参数1.0 表示拖拽滑动的敏感度,一般为1.0
// 第三个参数是一个自己实现的Callback,用来处理具体拖拽滑动行为的
- 将事件拦截和事件处理都交给ViewDragHelper来处理
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
// 如果当前事件ACTION_CANCEL或者ACTION_UP,停止一切拖拽处理
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mViewDragHelper.cancel();
return false;
}
// 必须调用mViewDragHelper.shouldInterceptTouchEvent(ev),让事件拦截在mViewDragHelper自己处理
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// 调用mViewDragHelper.processTouchEvent(ev); 将当前事件交给mViewDragHelper处理
mViewDragHelper.processTouchEvent(ev);
return true;
}
- 创建ViewDragCallback 继承自ViewDragHelper.Callback,处理具体的操作
先看下效果:
可以看到我们处理水平拖动,并没有处理当前view滑动到边缘的情况,一般而言,我们只希望当前view在ViewGroup内移动。
即:最小>=paddingleft,最大<=ViewGroup.getWidth()-paddingright-child.getWidth
我们对clampViewPositionHorizontal做下更改
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
Log.d(TAG,"left is :"+left+" dx is :"+dx);
int paddingLeft = child.getPaddingLeft();
int maxLeft = getWidth() - child.getWidth() - getPaddingRight();
if (left < paddingLeft) { // 当前child已经拖动到允许的最左边
left = paddingLeft;
}
if (left > maxLeft) { // 当前child已经拖动到允许的最右边
left = maxLeft;
}
return left;
}
此时效果如下:
可以看到此时已经正确的处理了view滑动到边缘的情况
垂直滑动
下面参照上面的水平滑动,实现同样的垂直滑动功能
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
int paddingTop = child.getPaddingTop();
Log.d(TAG,"left is :"+top+" dx is :"+dy+" paddingTop is :"+paddingTop);
int maxTop = getHeight() - child.getHeight() - getPaddingBottom();
if (top < paddingTop) {
top = paddingTop;
}
if (top > maxTop) {
top = maxTop;
}
return top;
}
此时效果如下:
处理滑动边缘
另外还可以设置处理当前ViewGroup的滑动边缘,比如下面的代码设置了可以处理滑动左边缘,此时当从当前ViewGroup的左边缘滑动,就会回调Callback中的onEdgeTouched方法.
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
@Override
public void onEdgeTouched(int edgeFlags, int pointerId) {
super.onEdgeTouched(edgeFlags, pointerId);
Log.d(TAG, "onEdgeTouched edgeFlags is :" + edgeFlags + " pointerId is :"+pointerId);
}
如果想在边缘滑动的时候根据滑动距离移动一个子view,可以通过实现onEdgeDragStarted方法,并在onEdgeDragStarted方法中手动指定要移动的子View
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
super.onEdgeDragStarted(edgeFlags, pointerId);
Log.d(TAG, "onEdgeDragStarted edgeFlags is :" + edgeFlags + " pointerId is :" + pointerId);
// 在父View内捕获指定的子view用于拖曳
mViewDragHelper.captureChildView(getChildAt(0),pointerId);
}
另外在ViewDragHelper中提供了下面几种边缘滑动的处理
松手返回到初始位置
如果需要实现松手返回到初始位置,需要做如下准备
- 定义一个Point记录当前被移动的view的初始位置
private Point mInitialPoint = new Point();
mDragFirst = getChildAt(0);
mDragFirst.postDelayed(new Runnable() {
@Override
public void run() {
mInitialPoint.set(mDragFirst.getLeft(),mDragFirst.getTop());
}
},0);
- 获取当前自定义的ViewGroup自己,后面会在松开手的时刻不断重绘自己
mSimpleLayout = (SimpleLayout) findViewById(R.id.rootLayout);
- 重写onViewReleased方法用来处理松手的回调,重写当前ViewGroup的computeScroll方法
// 当松手时候,xvel、yvel为离开屏幕时的速率
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
// 以松手前的滑动速度为初值,让捕获到的子View自动滚动到指定位置,只能在Callback的onViewReleased()中使用
mViewDragHelper.settleCapturedViewAt(mInitialPoint.x,mInitialPoint.y);
mSimpleLayout.invalidate();
// mSimpleLayout.requestLayout();
}
@Override
public void computeScroll() {
super.computeScroll();
// 在调用settleCapturedViewAt()、flingCapturedView()和smoothSlideViewTo()时,该方法返回true,一般重写父view的computeScroll方法,进行该方法判断
if (mViewDragHelper.continueSettling(true)) {// continueSettling方法返回true时,表示设置子view的位置还没有结束
invalidate();
}
}
此时效果如下:
简单的抽屉实现
下面我们通过自定义ViewGroup + ViewDragHelper实现一个简单的类似SlideMenu的抽屉效果
public class SelfDrawer extends LinearLayout {
private static final String TAG = "SimpleLayoutTest";
private View menuView;
private View contentView;
private ViewDragHelper mViewDragHelper;
public SelfDrawer(Context context) {
this(context, null);
}
public SelfDrawer(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SelfDrawer(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 创建mViewDragHelper
mViewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragCallback());
// 设置可以左边缘滑动
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
}
/**
* 重写onLayout方法,设置menu和content布局的位置, menuView初始位置应该在屏幕左侧外边,contentView应该沾满整个屏幕
* @param changed
* @param l
* @param t
* @param r
* @param b
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
menuView = getChildAt(0);
contentView = getChildAt(1);
Log.d(TAG, "menuView.getWidth() is :" + menuView.getMeasuredWidth() + " menuView.getHeight() is :" + menuView.getHeight() + " contentView.getWidth() is :" + contentView.getMeasuredWidth() + " contentView.getHeight() is :" + contentView.getHeight());
menuView.layout(-menuView.getWidth(),0,0,menuView.getHeight());
contentView.layout(0, 0, contentView.getWidth(), contentView.getHeight());
}
class ViewDragCallback extends ViewDragHelper.Callback {
/**
* tryCaptureView返回true表示menuView和contentView都可以响应拖拽处理
* @param child
* @param pointerId
* @return
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
/**
* 水平滑动,需要注意设置menuView和contentView的左侧滑动边缘值
* @param child
* @param left
* @param dx
* @return
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
int newLeft = left;
if (child == contentView) {
if (newLeft > menuView.getWidth()) {
newLeft = menuView.getWidth();
}
if (newLeft < 0) {
newLeft = 0;
}
}
if (child == menuView) {
if (newLeft > 0) {
newLeft = 0;
}
}
return newLeft;
}
// 手指释放的时候回调
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (contentView.getLeft() > menuView.getWidth() / 2) {
contentView.layout(menuView.getWidth(),0,menuView.getWidth() + contentView.getWidth(),contentView.getHeight());
menuView.layout(0,0,menuView.getWidth(),menuView.getHeight());
} else {
contentView.layout(0,0, contentView.getWidth(),contentView.getHeight());
menuView.layout(-menuView.getWidth(),0,0,menuView.getHeight());
}
invalidate();
}
//在边界拖动时回调
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
// 在左边界滑动时候,需要contentView跟着滑动,随后在onViewPositionChanged方法中,重新设置contentView和menuView的位置
mViewDragHelper.captureChildView(contentView, pointerId);
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == contentView) {
int menuLeft = -menuView.getWidth() + left;
menuView.layout(menuLeft,0,menuLeft + menuView.getWidth(),menuView.getHeight());
}
if (changedView == menuView) {
int contentLeft = menuView.getWidth() + left;
contentView.layout(contentLeft,0,contentLeft + contentView.getWidth(),contentView.getHeight());
}
invalidate();
}
}
// 重写computeScroll实现平滑的过度
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper.continueSettling(true)) {
invalidate();
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
// 测量子元素,设置其测量值大小
measureChildren(widthMeasureSpec,heightMeasureSpec);
setMeasuredDimension(widthSize, heightSize);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
// 如果当前事件ACTION_CANCEL或者ACTION_UP,停止一切拖拽处理
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
mViewDragHelper.cancel();
return false;
}
// 必须调用mViewDragHelper.shouldInterceptTouchEvent(ev),让事件拦截在mViewDragHelper自己处理
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
// 调用mViewDragHelper.processTouchEvent(ev); 将当前事件交给mViewDragHelper处理
mViewDragHelper.processTouchEvent(ev);
return true;
}
}
在布局中使用
<?xml version="1.0" encoding="utf-8"?>
<com.viewdrag.demo.SelfDrawer 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:orientation="horizontal"
android:id="@+id/root"
tools:showIn="@layout/activity_drawer">
<LinearLayout
android:layout_width="250dp"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#71dab5"
>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorAccent"
android:layout_marginLeft="100dp"
>
</LinearLayout>
</com.viewdrag.demo.SelfDrawer>
此时效果如下:
右滑退出activity
先说下思路
1. 创建一个自定义布局,绑定 Activity把layout加到decorview上
2. 在自定义布局中,处理手势滑动等效果
创建自定义布局
public class MySwipeBack extends FrameLayout {
private View mContentView;
private Activity mActivity;
private ViewDragHelper mViewDragHelper;
public MySwipeBack(Context context) {
this(context, null);
}
public MySwipeBack(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public MySwipeBack(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 创建ViewDragHelper,并设置可以从屏幕左边滑动
mViewDragHelper = ViewDragHelper.create(this,1.0f,new ViewDragHelperCallBack());
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
}
// 将事件处理交给mViewDragHelper
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
// 重写computeScroll,交给mViewDragHelper处理,用来平滑过度
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper.continueSettling(true)) {
invalidate();
}
}
}
创建ViewDragHelperCallBack
class ViewDragHelperCallBack extends ViewDragHelper.Callback {
/**
* 对于子view的拖拽,不予处理
* @param child
* @param pointerId
* @return
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return false;
}
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
super.onEdgeDragStarted(edgeFlags, pointerId);
mViewDragHelper.captureChildView(mContentView,pointerId);
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return Math.max(0, left);
}
/**
* 当手松开的时候,判断当前mContentView也就是DecorView的第一个子元素是否超过屏幕一半
* @param releasedChild
* @param xvel
* @param yvel
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int left = releasedChild.getLeft();
boolean needFinish = left > getWidth() / 2 ? true : false;
if (needFinish) {
mActivity.finish();
} else {
mContentView.layout(0,0,getWidth(),getHeight());
}
invalidate();
}
}
绑定 Activity把layout加到decorview上
public void attachActivity(Activity activity) {
mActivity = activity;
ViewGroup decor = (ViewGroup) activity.getWindow().getDecorView();
View content = decor.getChildAt(0);
mContentView = content;
decor.removeView(content);
addView(content);
decor.addView(this);
}
这里就是把DecorView的子元素添加到当前布局中,然后将当前布局添加到DecorView
Activity中处理
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
MySwipeBack mySwipeBack = new MySwipeBack(this);
mySwipeBack.attachActivity(this);
}
另外需要将当前activity背景设置为透明,否则在滑动的时候,看不到上一个activity
<style name="AppTheme.ActivityTranslant">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsTranslucent">true</item>
</style>
此时效果如下:
滑动删除
有了上面的分析,模仿一个滑动删除,先看下效果:
自定义布局MySwipeDelete
public class MySwipeDelete extends LinearLayout {
private View mContentView;
private View mDeleteView;
private ViewDragHelper mViewDragHelper;
private int mContentWidth;
private int mDeleteWidth;
public MySwipeDelete(Context context) {
this(context, null);
}
public MySwipeDelete(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MySwipeDelete(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mViewDragHelper = ViewDragHelper.create(this,1.0f,new ViewDragHelperCallBack());
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// 获取mContentView和mDeleteWidth宽度
mContentView = getChildAt(0);
mDeleteView = getChildAt(1);
mContentWidth = mContentView.getMeasuredWidth();
mDeleteWidth = mDeleteView.getMeasuredWidth();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
class ViewDragHelperCallBack extends ViewDragHelper.Callback {
/**
* 设置只有mContentView可以拖动
* @param child
* @param pointerId
* @return
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mContentView;
}
/**
* 水平拖动,需要限定水平拖动左边的范围
* @param child
* @param left
* @param dx
* @return
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
int newLeft = left;
if (left < -mDeleteWidth) {
newLeft = -mDeleteWidth;
}
if (left > 0) {
newLeft = 0;
}
return newLeft;
}
/**
* 当mContentView水平移动的时候,同时移动mDeleteView
* @param changedView
* @param left
* @param top
* @param dx
* @param dy
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
mDeleteView.layout(mContentWidth + left, 0, mContentWidth + left + mDeleteWidth, mDeleteView.getHeight());
invalidate();
}
/**
* 手指释放的时候,根据当前位置判断是否需要打开或者关闭mDeleteView
* @param releasedChild
* @param xvel
* @param yvel
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
int left = releasedChild.getLeft();
if (Math.abs(left) > mDeleteWidth / 2) {
mContentView.layout(-mDeleteWidth,0,mContentWidth - mDeleteWidth,mContentView.getHeight());
mDeleteView.layout(mContentWidth - mDeleteWidth,0,mContentWidth,mContentView.getHeight());
} else {
mContentView.layout(0,0,mContentWidth,mContentView.getHeight());
mDeleteView.layout(mContentWidth,0,mContentWidth + mDeleteWidth,mContentView.getHeight());
}
invalidate();
}
}
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper.continueSettling(true)) {
invalidate();
}
}
}
使用MySwipeDelete
<?xml version="1.0" encoding="utf-8"?>
<com.example.swipedelete.MySwipeDelete xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="80dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:orientation="horizontal"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#f1f1f1"
android:src="@drawable/ic_launcher"
/>
<TextView
android:text="testtest"
android:background="#f1f1f1"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="160dp"
android:layout_height="match_parent"
android:orientation="horizontal"
>
<TextView
android:text="置顶"
android:gravity="center"
android:textColor="#f5f0f0"
android:textSize="16sp"
android:background="#acbbc2"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="80dp" />
<TextView
android:text="删除"
android:gravity="center"
android:textColor="#f5f0f0"
android:textSize="16sp"
android:background="#ef5d5d"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="80dp" />
</LinearLayout>
</com.example.swipedelete.MySwipeDelete>
创建RecycleViewAdapter
public class TecRecyclerAdapter extends RecyclerView.Adapter<TecRecyclerAdapter.RecyclerHolder> {
private List<String>newsList = new ArrayList<>();
private Context mContext;
private RecyclerHolder mCurrentHolder;
private int mCurrentPosition;
public TecRecyclerAdapter(List<String> newsList, Context mContext) {
this.newsList = newsList;
this.mContext = mContext;
}
@Override
public RecyclerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_view,parent,false);
return new RecyclerHolder(itemView);
}
@Override
public void onBindViewHolder(RecyclerHolder holder, int position) {
holder.textViewNews.setText(newsList.get(position));
mCurrentPosition = position;
holder.toDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(mContext,"adfadfasd",Toast.LENGTH_LONG).show();
}
});
}
@Override
public int getItemCount() {
return newsList.size();
}
class RecyclerHolder extends RecyclerView.ViewHolder {
private TextView textViewNews;
private TextView toTop;
private TextView toDelete;
public RecyclerHolder(View itemView) {
super(itemView);
textViewNews = (TextView) itemView.findViewById(R.id.id_news);
toTop = (TextView) itemView.findViewById(R.id.id_toTop);
toDelete = (TextView) itemView.findViewById(R.id.id_toDelete);
}
}
}
加载并显示数据
public class DeleteActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.delete_layout);
mRecyclerView = (RecyclerView) findViewById(R.id.id_news_recycler);
List<String> newLists= new ArrayList<>();
newLists.add("新闻最佳TOP10......");
newLists.add("aaaaaaa");
newLists.add("bbbbbbbb");
newLists.add("ccccc");
newLists.add("dddddddddd");
TecRecyclerAdapter recyclerAdapter = new TecRecyclerAdapter(newLists,this);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(),
DividerItemDecoration.HORIZONTAL_LIST);
mRecyclerView.addItemDecoration(dividerItemDecoration);
mRecyclerView.setAdapter(recyclerAdapter);
}
}
此时效果如下:
ok,今天就到这了。