当前位置: 首页 > news >正文

福州建网站 做网页/拉新推广怎么找渠道

福州建网站 做网页,拉新推广怎么找渠道,有没有做牛羊角的网站,前端网站做中 英文LZ-Says:自从国庆回来,状态就一直不好,乱七八糟的事儿,真是不知道如何开口,相应的学习计划也下降的几乎为0了。还是要硬着头皮继续上,越不动,越懒,当某天习惯了可就难改了&#xff0…

LZ-Says:自从国庆回来,状态就一直不好,乱七八糟的事儿,真是不知道如何开口,相应的学习计划也下降的几乎为0了。还是要硬着头皮继续上,越不动,越懒,当某天习惯了可就难改了,加油~

前言

前几天写了一篇RecyclerView初步使用,有兴趣的可以看下,地址如下:

Android Study Material Design之:这可能是RecyclerView最全解析(一)

而今天在此基础上继续深入,让大家更好的掌握RecyclerView~

本文目标

学习完本篇之后,你会掌握如下技能:

  • 为RecyclerView添加分割线;

  • 为RecyclerView装饰更美的头部以及底部;

  • 让RecyclerView更人性化,添加交互动画。

效果简阅

光说不练假把式,没图,多不爽?

这里写图片描述

进入Study模式

- - - - - - 前方高能,注意哦- - - - - -

一、添加分割线

首先我们来回顾下ListView是如何添加分割线,如下:

    <ListView
        android:layout_width="wrap_content"android:layout_height="wrap_content"android:listSelector="@color/background" />

而在RecyclerView中,细心的你会发现,卧槽,怎么找不到这个属性呢?

这里就不得不再次说下RecyclerView这个东西:高内聚-低耦合,正是由于RecyclerView具有此特性,才方便我们可能自由的定制我们的分割线,想怎么玩就怎么玩,But,我们需要依赖一个特别的东西,如下:

ItemDecoration: 作用就是在RecyclerView上绘制(定制)分割线,而其下还有俩个关键方法需要我们来关注,如下。

  • getItemOffsets: 获得item偏移量;

  • onDraw: RecycleView回调此函数,需自己实现绘制分割线

基于上面,还要和RecyclerView中的addItemDecoration()配合使用,大话不多说,我们首先了解下编写思路。

重写方法之后,你需要做如下几步:

  • 1. 分割线样式选择

    既然是绘制分割线,那总的有分割线才是,我们先使用系统提供分割线来撸一波

  • 2. 确定当前显示类型

    分割线显示,就拿最简单的LinearLayout举例,默认水平,还可设置垂直,那我们的分割线同理,不光有默认绘制方向,对外也能提供入口

  • 3. 获取item偏移量

    获取item偏移量,也就是获取矩形的区域,这点不难理解,我们绘制分割线,是通过onDraw()方法去绘制,那么绘制的点又是怎么确定的呢?附上简图一张。

    这里写图片描述

    上图所示,分割线的分步,在于item的显示,如何纵向排列,分割线在俩个item之间,反之,同理,只是方向不一样而已。
    大家切记,下面撸码会用到。

  • 4. 绘制分割线

    如第3点所述,根据item显示方向不同,我们分割线的绘制也不相同

基本思路如上,具体代码中会体现:

package com.materialdesignstudy.ltem;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.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.LayoutParams;
import android.view.View;/*** 分割线 Created by HLQ on 2017/9/26*/
public class DividerItemDecoration extends RecyclerView.ItemDecoration {private int mOrientation = LinearLayoutManager.VERTICAL;private Drawable mDivider;private int[] attrs = new int[]{android.R.attr.listDivider};public DividerItemDecoration(Context context, int orientation) {// 引用系统属性样式TypedArray typedArray = context.obtainStyledAttributes(attrs);mDivider = typedArray.getDrawable(0);typedArray.recycle();setOrientation(orientation);}/*** 设置参数枚举类型 水平 or 垂直* @param orientation*/public void setOrientation(int orientation) {// 避免传入非法类型if (orientation != LinearLayoutManager.HORIZONTAL && orientation != LinearLayoutManager.VERTICAL) {throw new IllegalArgumentException("非法参数枚举类型");}mOrientation = orientation;}/*** 1. 获得条目偏移量** @param outRect* @param view* @param parent* @param state*/@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {// 首先获取条目之间的间隙宽度 也就是Rect矩形区域if (mOrientation == LinearLayoutManager.VERTICAL) { // 垂直outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());} else { // 水平outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);}}/*** 2. RecycleView回调此函数 开发者需自己实现绘制分割线** @param c* @param parent* @param state*/@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {if (mOrientation == LinearLayoutManager.VERTICAL) { // 垂直drawVertical(c, parent);} else { // 水平drawHorizontal(c, parent);}super.onDraw(c, parent, state);}/*** 绘制水平分割线** @param c* @param parent*/private void drawVertical(Canvas c, RecyclerView parent) {// 考虑父容器padding值int left = parent.getPaddingLeft();// 绘制右侧时需要减去右侧padding值int right = parent.getWidth() - parent.getPaddingRight();// 获取父容器下子控件个数 也就是item个数int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {View child = parent.getChildAt(i);RecyclerView.LayoutParams params = (LayoutParams) child.getLayoutParams();// 高度等于子控件底部加margin加y轴值int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));// 底部等于高度加当前实际高度int bottom = top + mDivider.getIntrinsicHeight();// 设置绘制位置mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}private void drawHorizontal(Canvas c, RecyclerView parent) {int top = parent.getPaddingTop();int bottom = parent.getHeight() - parent.getPaddingBottom();int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {View child = parent.getChildAt(i);RecyclerView.LayoutParams params = (LayoutParams) child.getLayoutParams();int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));int right = left + mDivider.getIntrinsicHeight();// 设置绘制位置mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}}

运行后查看效果如下:

这里写图片描述          这里写图片描述

LinearLayout分割线绘制完成,那么GirdView的呢?

首先我们分析下俩者区别,很简单,一个单一,一个多嘛。
LinearLayout只有俩种状态,我们也只需要绘制横向或者纵向即可,而GirdView,则需要绘制横向以及纵向俩种,其实也就是改了部分而已,关键代码如下:

    @Overridepublic void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {// 偏移量 代表左上右下分别对应上一个的偏移值int right = mDivider.getIntrinsicWidth();int bottom = mDivider.getIntrinsicHeight();if (isLastRow(parent)) { // 代表当前是最后一行 不绘制底部bottom = 0;}if (isLastCol(itemPosition, parent)) { // 代表当前是最后一列 不绘制右侧right = 0;}outRect.set(0, 0, right, bottom);}/*** 是否是最后一行** @return*/private boolean isLastRow(RecyclerView parent) {int spanCount = getSpanCount(parent);RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();if (layoutManager instanceof GridLayoutManager) {int childCount = parent.getAdapter().getItemCount();int lastRowCount = childCount % spanCount;if (lastRowCount == 0 || lastRowCount < spanCount) { // 最后一行情况:1)被整除 2)小于列数return true;}}return false;}/*** 是否是最后一列** @return*/private boolean isLastCol(int itemPosition, RecyclerView parent) {RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();if (layoutManager instanceof GridLayoutManager) {// 拿到当前有多少列int spanCount = getSpanCount(parent);if ((itemPosition + 1) % spanCount == 0) {return true;}}return false;}/*** 获取列数* @param parent* @return*/private int getSpanCount(RecyclerView parent) {RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();if (layoutManager instanceof GridLayoutManager) {GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;// 拿到当前有多少列int spanCount = gridLayoutManager.getSpanCount();return spanCount;}return 0;}

效果如下:

这里写图片描述

嗯哼,是不是感觉一套下来感觉思路也开拓了许多呢?

二、来一场模仿秀:为RecyclerView添加头部和底部

在此,首先为大家附上效果图,如下:

这里写图片描述

同理,RecyclerView的添加头部以及底部,我们同样可参考ListView源码进行操作,那么接下来,我们看看ListView中源码是如何进行操作的,而我们又该如何进行改造,从而实现我们的效果呢?

打开源码,Alt+7查看当前包含方法,找到ListView的添加头部以及底部代码部分,如下图:

这里写图片描述

下面,我们进行简易分析。

首先找到addHeaderView方法,如下:

    /*** Add a fixed view to appear at the top of the list.在list上添加一个view* @param v The view to add.*/public void addHeaderView(View v) {addHeaderView(v, null, true);}

没啥特别的,传入我们要添加的View,其他俩个参数啥意思不知道,只能继续往下看,代码和注释并存。

    /*** Add a fixed view to appear at the top of the list. * @param v The view to add. view被添加* @param data Data to associate with this view view数据源* @param isSelectable whether the item is selectable 当前item是否被选中*/public void addHeaderView(View v, Object data, boolean isSelectable) {// 校验当前view父容器是否非空 并且 view的父容器不是当前容器if (v.getParent() != null && v.getParent() != this) { // 代表当前已经为父容器添加了子视图,也就是我们的头布局 必须remove掉方才可能继续添加 这点比较局限性if (Log.isLoggable(TAG, Log.WARN)) {Log.w(TAG, "The specified child already has a parent. "+ "You must call removeView() on the child's parent first.");}}// 以下为数据常量初始化final FixedViewInfo info = new FixedViewInfo();info.view = v;info.data = data;info.isSelectable = isSelectable;// 添加容器mHeaderViewInfos.add(info);mAreAllItemsSelectable &= isSelectable;// 校验当前adapter是否有效// Wrap the adapter if it wasn't already wrapped.if (mAdapter != null) {if (!(mAdapter instanceof HeaderViewListAdapter)) { // 如果当前adapter不属于HeaderViewListAdapter 这里又做了哪儿些操作呢?wrapHeaderListAdapterInternal();}// In the case of re-adding a header view, or adding one later on,// we need to notify the observer.if (mDataSetObserver != null) {mDataSetObserver.onChanged();}}}

怀着疑问,我们继续往下看~

    protected void wrapHeaderListAdapterInternal() { // 这里对adapter再次进行一次封装 之前的adapter的类型为:ListAdapter mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, mAdapter);}protected HeaderViewListAdapter wrapHeaderListAdapterInternal( ArrayList<ListView.FixedViewInfo> headerViewInfos,ArrayList<ListView.FixedViewInfo> footerViewInfos,ListAdapter adapter) { return new HeaderViewListAdapter(headerViewInfos, footerViewInfos, adapter); // 它的处理便是真正封装内容 将adapter转变成HeaderViewListAdapter}public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos,ArrayList<ListView.FixedViewInfo> footerViewInfos,ListAdapter adapter) {mAdapter = adapter;mIsFilterable = adapter instanceof Filterable;// 如果headerViewInfos等于null 代表属于item项实际body部分 也就是我们正常显示的部分 if (headerViewInfos == null) {mHeaderViewInfos = EMPTY_INFO_LIST;} else { // 代表当前是头布局 headerViewInfosmHeaderViewInfos = headerViewInfos;}// 如果footerViewInfos等于null 代表属于item项实际body部分 也就是我们正常显示的部分 if (footerViewInfos == null) {mFooterViewInfos = EMPTY_INFO_LIST;} else { // 代表当前是底布局 footerViewInfosmFooterViewInfos = footerViewInfos;}mAreAllFixedViewsSelectable =areAllListInfosSelectable(mHeaderViewInfos)&& areAllListInfosSelectable(mFooterViewInfos);}

看的是不是有点晕乎,为什么中间又跑出来一个adapter呢?这个问题,我们画个简图简单说明下:

这里写图片描述

  • 如上图所示,这是ListView最终展示的效果,那么为什么中间还会有个adapter呢?

    最初,父容器mAdapter为ListAdapter,当添加了头部时,此时的mAdapter变转化为HeaderViewAdapter,而添加了尾部时,又转化为FooterViewAdapter,而真正数据展示,也就是body部分却再次回归ListAdapter。其中的过程很像是中间代理,有木有一种分工明确的感觉,下面再举个例子。

    好比工厂生产手机,他们对外提供的只是一部完整的手机,而他们不会生产其中的零件,看到这里,大家有没有是懂非懂的感觉?
    有还是没有,我们都该撸码了骚年。

那么下面,我们依据ListView上面的简单分析源码进行我们的模仿秀。

既然是模仿,首先我们需要搭建一个中间层,也就是ListView的HeaderViewAdapter,如下:

package com.materialdesignstudy.adapter;import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;import java.util.ArrayList;/*** Created by HLQ on 2017/10/12* 模仿ListView添加头部时 中间的adapter*/
public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter {private RecyclerView.Adapter mAdapter;private ArrayList<View> mHeaderViewInfos;private ArrayList<View> mFooterViewInfos;public HeaderViewRecyclerAdapter(ArrayList<View> headerViewInfos, ArrayList<View> footerViewInfos, RecyclerView.Adapter adapter) {// 这里面的逻辑和ListView中很相似,不过相对来说我们这里更为简单一些// 这里 我们只需要考虑 三种情况即可 头布局 正常body 尾布局mAdapter = adapter;if (headerViewInfos == null) {mHeaderViewInfos = new ArrayList<>();} else {mHeaderViewInfos = headerViewInfos;}if (footerViewInfos == null) {mFooterViewInfos = new ArrayList<>();} else {mFooterViewInfos = footerViewInfos;}}/*** 判断当前条目类型 通过类型指定相关视图** @param position* @return*/@Overridepublic int getItemViewType(int position) {int numHeaders = getHeadersCount();// 头部if (position < numHeaders) {return RecyclerView.INVALID_TYPE;}// 正常内容载体int adapterCount = 0;int adjPosition = position - numHeaders;if (mAdapter != null) {adapterCount = mAdapter.getItemCount();if (adjPosition < adapterCount) {return mAdapter.getItemViewType(adjPosition);}}// 底部return RecyclerView.INVALID_TYPE - 1;}@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {if (viewType == RecyclerView.INVALID_TYPE) {// 头部return new HeaderViewHolder(mHeaderViewInfos.get(0));} else if (viewType == RecyclerView.INVALID_TYPE - 1) {return new HeaderViewHolder(mFooterViewInfos.get(0));}return mAdapter.onCreateViewHolder(parent, viewType);}@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {int numHeaders = getHeadersCount();// 头部if (position < numHeaders) {return;}int adapterCount = 0;int adjPosition = position - numHeaders;if (mAdapter != null) {adapterCount = mAdapter.getItemCount();if (adjPosition < adapterCount) {mAdapter.onBindViewHolder(holder, adjPosition);return;}}}@Overridepublic int getItemCount() {if (mAdapter != null) {return getFootersCount() + getHeadersCount() + mAdapter.getItemCount();} else {return getFootersCount() + getHeadersCount();}}public int getFootersCount() {return mFooterViewInfos.size();}public int getHeadersCount() {return mHeaderViewInfos.size();}private static class HeaderViewHolder extends RecyclerView.ViewHolder {public HeaderViewHolder(View itemView) {super(itemView);}}}

其次,需要我们自定义RecyclerView,也可以理解为对之前的RecyclerView进行改造,使其具有添加头部以及尾部的功能,如下:

package com.materialdesignstudy.weight;import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;import com.materialdesignstudy.adapter.HeaderViewRecyclerAdapter;import java.util.ArrayList;/*** 为RecycleView添加头部Created by HLQ on 2017/10/12*/public class MyRecyclerView extends RecyclerView {// 存放头部布局容器private ArrayList<View> mHeaderViewInfos = new ArrayList<>();// 存放底部布局容器private ArrayList<View> mFooterViewInfos = new ArrayList<>();private Adapter mAdapter;public MyRecyclerView(Context context) {super(context);}public MyRecyclerView(Context context, AttributeSet attrs) {super(context, attrs);}public MyRecyclerView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public void addHeaderView(View view) {mHeaderViewInfos.add(view);if (mAdapter != null) {if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);}}}public void addFooterView(View view) {mFooterViewInfos.add(view);if (mAdapter != null) {if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, mAdapter);}}}@Overridepublic void setAdapter(Adapter adapter) {if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) {mAdapter = new HeaderViewRecyclerAdapter(mHeaderViewInfos, mFooterViewInfos, adapter);} else {mAdapter = adapter;}super.setAdapter(mAdapter);}
}

主布局中引用我们改造后的RecyclerView,如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"tools:context="com.materialdesignstudy.activity.WrapRecycleViewActivity"><com.materialdesignstudy.weight.MyRecyclerView
        android:id="@+id/id_my_recycleview"android:layout_width="match_parent"android:layout_height="match_parent" /></LinearLayout>

编写对应的Adapter使其填充数据。

package com.materialdesignstudy.adapter;import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;import com.materialdesignstudy.R;import java.util.List;/*** Created by HLQ on 2017/10/17*/public class MyWrapRecycleVlewAdapter extends RecyclerView.Adapter<MyWrapRecycleVlewAdapter.ViewHolder> {private List<String> mStrList;public MyWrapRecycleVlewAdapter(List<String> strList) {this.mStrList=strList;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {LayoutInflater layoutInflater=LayoutInflater.from(parent.getContext());View view=layoutInflater.inflate(R.layout.item_recy,parent,false);ViewHolder holder=new ViewHolder(view);return holder;}@Overridepublic void onBindViewHolder(ViewHolder holder, int position) {holder.tvText.setText(mStrList.get(position));}@Overridepublic int getItemCount() {return mStrList.size();}public class ViewHolder extends RecyclerView.ViewHolder{public TextView tvText;public ViewHolder(View itemView) {super(itemView);tvText= (TextView) itemView.findViewById(R.id.item_tv);}}}

主Activity中实例化模拟数据,如下:

package com.materialdesignstudy.activity;import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;import com.materialdesignstudy.R;
import com.materialdesignstudy.adapter.MyWrapRecycleVlewAdapter;
import com.materialdesignstudy.weight.MyRecyclerView;import java.util.ArrayList;
import java.util.List;/****/
public class WrapRecycleViewActivity extends AppCompatActivity {private MyRecyclerView recyclerView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_wrap_recycle);recyclerView = (MyRecyclerView) findViewById(R.id.id_my_recycleview);TextView tvHeader = new TextView(this);LinearLayout.LayoutParams headerParam = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 120);tvHeader.setLayoutParams(headerParam);tvHeader.setText("我是HeaderView");tvHeader.setBackgroundColor(Color.YELLOW);recyclerView.addHeaderView(tvHeader);TextView tvFooter = new TextView(this);LinearLayout.LayoutParams footerParam = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 80);tvFooter.setLayoutParams(footerParam);tvFooter.setText("我是FooterView");tvFooter.setBackgroundColor(Color.BLUE);recyclerView.addFooterView(tvFooter);List<String> strList=new ArrayList<>();for (int i = 0; i <10 ; i++) {strList.add("item:"+i);}MyWrapRecycleVlewAdapter myAdapter=new MyWrapRecycleVlewAdapter(strList);recyclerView.setLayoutManager(new LinearLayoutManager(this));recyclerView.setAdapter(myAdapter);}
}

到现在为止,我们已经完成了RecyclerView添加头部以及尾部,大家可能有点蒙,不过别着急,回过头好好看下我们刚刚分析过的ListView源码,虽然简单,但是毕竟主要的都在里面,而在实际的代码中,大家能看出高仿的痕迹~

三、为RecyclerView添加交互动画

如文章开头说所示,本小节目标就是给RecyclerView添加交互动画,那么什么是交互动画呢?所谓的交互都有什么呢?

  • 拖拽 根据方向可分为上下移动item并实时更新item位置,左右侧滑删除;

  • 动画 以及显示效果 总不能光秃秃的傻不啦叽的吧

这里不得不介绍官方为我们提供的一个Helper帮助类: ItemTouchHelper 。而我们实现也主要依旧此类。

它的使用也是很nice,只需要进行俩步,1:实例化帮助类; 2:绑定RecyclerView。 就好像下面示例一样nice。

        // RecycleView item触摸帮助类 例如 滑动 拖动helper =new ItemTouchHelper(new BaseItemTouchHelperCallback(mAdapter));// 绑定RecycleViewhelper.attachToRecyclerView(mRecycleView);

而针对ItemTouchHelper,我们在实际使用中应该手动创建HelperCallback并继承ItemTouchHelper.Callback,以便于我们在回调中进行具体细节操作,这里简单列举下关键要重写的方法及其作用:

ItemTouchHelper:官方提供item touch helper

  • getMovementFlags(): 判断用户当前操作,例如:上下拖动 左右侧滑;

  • onMove(): 用户移动时回调;

  • onSwiped(): 侧滑时回调;

  • isLongPressDragEnabled(): 是否允许长按拖拽效果;

  • isItemViewSwipeEnabled(): 是否允许开启侧滑效果;

  • onSelectedChanged(): 选择状态改变;

  • clearView(): 重置View,也代表可以在这里恢复View状态;

  • onChildDraw(): 重绘item.

定义Item Touch Move Listener,用于回调监听拖动以及侧滑事件,如下:

package com.materialdesignstudy.itemtouch;/*** Created by HLQ on 2017/10/18*/
public interface ItemTouchMoveListener {/*** 拖拽时调用并进行相应操作 例如刷新界面UI** @param fromPosition 从某个位置开始拖动* @param toPosition   到某个位置结束拖动* @return*/boolean onItemMove(int fromPosition, int toPosition);/*** 移动Item** @param position 移除位置* @return*/boolean onItemRemove(int position);}

Activity中模拟测试数据,并绑定helper帮助类:

    ...private RecyclerView mRecycleView;private ItemAdapter mAdapter;private ItemTouchHelper helper;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_item_touch);mRecycleView = (RecyclerView) findViewById(R.id.id_item_touch);mRecycleView.setLayoutManager(new LinearLayoutManager(this));mAdapter = new ItemAdapter(getData(),this);mRecycleView.setAdapter(mAdapter);// RecycleView item触摸帮助类 例如 滑动 拖动helper =new ItemTouchHelper(new BaseItemTouchHelperCallback(mAdapter));// 绑定RecycleViewhelper.attachToRecyclerView(mRecycleView);}private List<String> getData() {List<String> strList = new ArrayList<>();for (int i = 0; i < 30; i++) {strList.add("今天天气好晴朗,处处好风光,报数:" + i);}return strList;}...

Adapter中实现接口,并对接口回调进行处理,另外,还需要对数据进行绑定,但是需要注明的有俩点:

  • 拖动时,需要将item替换移动过的每个item,刷新界面UI的同时,也需要更新每个item的position;

  • 侧滑时,只需要将List中item项remove并更新当前remove掉的UI

package com.materialdesignstudy.itemtouch;import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;import com.materialdesignstudy.R;import java.util.Collections;
import java.util.List;/*** Created by HLQ on 2017/10/17*/
public class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> implements ItemTouchMoveListener {private StartDragListener mStartDragListener;private List<String> mStrList;public ItemAdapter(List<String> strList, StartDragListener dragListener) {this.mStrList = strList;mStartDragListener = dragListener;}@Overridepublic ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {LayoutInflater inflater = LayoutInflater.from(parent.getContext());View view = inflater.inflate(R.layout.item_touch, parent, false);ViewHolder viewHolder = new ViewHolder(view);return viewHolder;}@Overridepublic void onBindViewHolder(final ViewHolder holder, int position) {holder.tvTitle.setText(mStrList.get(position));}@Overridepublic int getItemCount() {return mStrList.size();}@Overridepublic boolean onItemMove(int fromPosition, int toPosition) {Collections.swap(mStrList, fromPosition, toPosition); // 数据交换notifyItemMoved(fromPosition, toPosition); // 刷新界面UIreturn true;}@Overridepublic boolean onItemRemove(int position) {// 移除itemmStrList.remove(position);// 更新移除掉item位置notifyItemRemoved(position);return true;}class ViewHolder extends RecyclerView.ViewHolder {private ImageView ivIcon;private TextView tvTitle;public ViewHolder(View itemView) {super(itemView);tvTitle = (TextView) itemView.findViewById(R.id.id_app_item_touch_title);ivIcon = (ImageView) itemView.findViewById(R.id.id_app_item_touch_icon);}}}

现在,我们来处理下关于我们定义的Callback业务流程:

package com.materialdesignstudy.itemtouch;import android.graphics.Canvas;
import android.graphics.Color;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;/*** Created by HLQ on 2017/10/17*/
public class BaseItemTouchHelperCallback extends ItemTouchHelper.Callback {private ItemTouchMoveListener mMoveListener;public BaseItemTouchHelperCallback(ItemTouchMoveListener moveListener) {this.mMoveListener = moveListener;}// 判断当前操作@Overridepublic int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {// 判断用户当前的操作:向上、向下拖动 左右侧滑// 而所对应的状态标识分别为:ItemTouchHelper.UP ItemTouchHelper.DOWN ItemTouchHelper.LEFT ItemTouchHelper.RIGHT
//        int upFlag=ItemTouchHelper.UP; // 1 0*0001
//        int downFlag=ItemTouchHelper.DOWN; // 2 0*0010// 监听拖动方向为 上下int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;// 监听侧滑方向
//        int swipeFlags = 0; // 不监听int swipeFlags = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT; // 监听左右侧滑动return makeMovementFlags(dragFlags, swipeFlags);}// 移动时回调@Overridepublic boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {if (viewHolder.getItemViewType() != target.getItemViewType()) {return false;}boolean result = mMoveListener.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());return result;}// 侧滑时回调@Overridepublic void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {mMoveListener.onItemRemove(viewHolder.getAdapterPosition());}// 是否允许长按拖拽效果@Overridepublic boolean isLongPressDragEnabled() {return true;}@Overridepublic boolean isItemViewSwipeEnabled() {return true;}@Overridepublic void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {// 判断选中状态if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { // 不是闲置状态viewHolder.itemView.setBackgroundColor(Color.BLUE);}super.onSelectedChanged(viewHolder, actionState);}@Overridepublic void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {viewHolder.itemView.setBackgroundColor(Color.WHITE);// 关于复用导致空白 解决方案一
//        viewHolder.itemView.setAlpha(1);
//        viewHolder.itemView.setScaleX(1);
//        viewHolder.itemView.setScaleY(1);super.clearView(recyclerView, viewHolder);}// 重绘item@Overridepublic void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {float alpha = 1 - Math.abs(dX) / viewHolder.itemView.getWidth();if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { // 侧滑时增加特效// dx:水平方向移动的偏移量(负:往左 正:往右) 范围:0~View.getWidth() 0~1// 透明度viewHolder.itemView.setAlpha(alpha);// 缩放viewHolder.itemView.setScaleX(alpha);viewHolder.itemView.setScaleY(alpha);}if (alpha == 0) { // item划出时 恢复之前状态 解决由于复用导致划出空白bug 方案二viewHolder.itemView.setAlpha(1);viewHolder.itemView.setScaleX(1);viewHolder.itemView.setScaleY(1);}// 判断滑动偏移量是否超出屏幕一半时 就设置其当前停留在一般的位置
//        if(Math.abs(dX)<=viewHolder.itemView.getWidth()/2){
//            viewHolder.itemView.setTranslationX(-0.5f*viewHolder.itemView.getWidth());
//        }else{
//            viewHolder.itemView.setTranslationX(dX);
//        }super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);}}

那么假设现在有个需要,当你点击item中的头像,也能进行上下拖动item呢?那我们又该如何处理呢?

同样很easy,定义拖拽接口,回调继续将事件传递下去即可,如下:

package com.materialdesignstudy.itemtouch;/*** Created by HLQ on 2017/10/18*/
public interface StartDragListener {/*** 该接口用于需要主动回调拖拽效果* @param viewHolder*/void onStartDrag(ItemAdapter.ViewHolder viewHolder);}

adapter绑定数据时,绑定touch事件(这里需要解释Activity传递的监听):

        holder.ivIcon.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {if (event.getAction() == MotionEvent.ACTION_DOWN) {mStartDragListener.onStartDrag(holder);}return false;}});

最后,实现StartDragListener接口,重写拖拽接口,将ViewHolder传递进去即可。

    @Overridepublic void onStartDrag(ItemAdapter.ViewHolder viewHolder) {helper.startDrag(viewHolder);}

OK啦~

GitHub查看地址

https://github.com/HLQ-Struggle/MaterialDesignStudy

结束

坚持到现在,有点心累了,各种问题接踵而来,解决完之后,自己只剩下疲倦了。

真想好好休息下哈~

想想各位小伙伴依然在坚挺,在努力,甩甩头,继续~

http://www.jmfq.cn/news/5253823.html

相关文章:

  • 南皮做网站/如何对一个网站进行seo
  • 做效果图的网站有哪些/怎样进行seo推广
  • 创意产品设计100例图片/seo外链平台热狗
  • 网络营销企业网站优化/百度排名
  • 室内装修设计联盟/石家庄seo代理商
  • 四川企业网站建设/杭州seo整站优化
  • 写作网站哪个最好/宁宁网seo
  • 唯美音乐图文网站建设/网站快速优化排名app
  • 戚墅堰做网站价格/线上营销怎么推广
  • 平台网站的策划设计/整合营销传播理论
  • 模板网站的域名是什么意思/seo英文
  • 假网站怎么制作/seo知识总结
  • 公司网站怎么突然多了好多友情链接如何删除/福州seo管理
  • 做网站的工具怎么使用/太原seo网络优化招聘网
  • 做精彩网站分析的方向是/今日竞彩足球最新比赛结果查询
  • 南阳做网站多少电话/培训课程开发
  • 网上怎么接单做网站/百度网盘搜索入口
  • 建设完网站成功后需要注意什么/优化人员配置
  • 长沙 网站开发报价/如何推广自己的产品
  • 招聘网站代做/seo团队
  • 广州网站(建设信科网络)/百度推广后台登陆首页
  • 怎么在后台设计网站/传统营销
  • vr模式的网站建设公司/友链交换平台
  • 律师网站设计/seo怎么做优化方案
  • 花桥网站制作/适合成人参加的培训班
  • 网站客户端ip做爬虫/百度贴吧入口
  • 电子商务网站建设基础项目实训报告/关键词分析软件
  • php做用户注册网站/如何在百度上做推广
  • 英文 网站 字体/酒店网络营销方式有哪些
  • 网站开发工作职责/app关键词优化