Android使用RecyclerView实现今日头条频道管理功能

使用过今日头条的伙计们对这个效果肯定很熟悉。拖拽可排序,点击标签后可以删除。今天我们采用RecyclerView来实现。

实现思路:

通过ItemTouchHelper来绑定RecyclerView的子控件触摸事件。
当滑动拖拽的时候,通知适配器来交换两个子控件的显示位置。
更改数据源,使数据源与子空间显示内容一致。
这就是实现的基本思路,是不是很简单?当然,首先要了解一下ItemTouchHelper这哥们儿是干啥的,有什么作用。

This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

It works with a RecyclerView and a Callback class, which configures what type of interactions are enabled and also receives events when user performs these actions.

Depending on which functionality you support, you should override onMove(RecyclerView, ViewHolder, ViewHolder) and / or onSwiped(ViewHolder, int).

This class is designed to work with any LayoutManager but for certain situations, it can be optimized for your custom LayoutManager by extending methods in the ItemTouchHelper.Callback class or implementing ItemTouchHelper.ViewDropHandler interface in your LayoutManager.

By default, ItemTouchHelper moves the items' translateX/Y properties to reposition them. You can customize these behaviors by overriding onChildDraw(Canvas, RecyclerView, ViewHolder, float, float, int, boolean) or onChildDrawOver(Canvas, RecyclerView, ViewHolder, float, float, int, boolean).

Most of the time you only need to override onChildDraw.

通过API文档的介绍,这个哥们儿是为RecyclerView工作的,他需要一个CallBack,可以回调RecyclerView的子控件滑动和拖拽事件,而且也可以通过这个CallBack重绘我们的子view。这就一目了然了嘛。通过使用ItemTouchHelper,可以很轻松的就实现了RecyclerView触摸事件的回调。换句话说,只要我们为RecyclerView 绑定了ItemTouchHelper之后,RecyclerView子控件的拖动和滑动事件已经帮我们实现了。我们所要做的就是在触摸事件之后,如何去改变去更新Adapter和改变我们的数据。

开始撸码:

public class ChannelActivity extends Activity {

  public RecyclerView rv;

  public List<DataBean> list = new ArrayList<>();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_channel);
    initData();
    initView();
  }

  private void initView() {

    rv = (RecyclerView) findViewById(R.id.rl_view);
    rv.setLayoutManager(new GridLayoutManager(this, 4));
    MyAdapter adapter = new MyAdapter(this, list);
    rv.setAdapter(adapter);
    //关联ItemTouchHelper
    ItemTouchHelper touchHelper = new ItemTouchHelper(new MyItemTouchCallBack(adapter));
    touchHelper.attachToRecyclerView(rv);

  }

  private void initData() {

    DataBean bean1 = new DataBean("体育", 0, "url");
    DataBean bean2 = new DataBean("新闻", 1, "url");
    DataBean bean3 = new DataBean("影视", 2, "url");
    DataBean bean4 = new DataBean("电视剧", 3, "url");
    DataBean bean5 = new DataBean("热点", 4, "url");
    DataBean bean6 = new DataBean("推荐", 5, "url");
    DataBean bean7 = new DataBean("屌丝男士", 6, "url");
    DataBean bean8 = new DataBean("音乐", 7, "url");
    DataBean bean9 = new DataBean("电影", 8, "url");

    list.add(bean1);
    list.add(bean2);
    list.add(bean3);
    list.add(bean4);
    list.add(bean5);
    list.add(bean6);
    list.add(bean7);
    list.add(bean8);
    list.add(bean9);
  }
}

自定义MyItemTouchCallBack

public class MyItemTouchCallBack extends ItemTouchHelper.Callback {

  private TouchInterface touchInterface;

  public MyItemTouchCallBack(TouchInterface touchInterface) {
    this.touchInterface = touchInterface;
  }

  @Override
  public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    //拖拽
    int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT;
    //滑出屏幕
    int swipeFlags = ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
    return makeMovementFlags(dragFlags, 0);
  }

  @Override
  public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

    int position_target = target.getLayoutPosition();
    int position = viewHolder.getLayoutPosition();
    //滑动事件回调到了Adapter,用来处理数据
    touchInterface.onMove(position, position_target);
    return true;
  }

  //标签动画持续时间,默认是250
  @Override
  public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy) {

    return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
  }

  /**
   * 是否可以长按拖拽,默认是true
   *
   * @return
   */
  @Override
  public boolean isLongPressDragEnabled() {
    return super.isLongPressDragEnabled();
  }

  /**
   * 标签划出去的回调,direction是滑动的方向
   *
   * @return
   */

  @Override
  public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
  }

}

Adapter类中处理数据

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

  private Context context;
  //是否显示delete
  public boolean isShow;

  public List<DataBean> getList() {
    return list;
  }

  public void setList(List<DataBean> list) {
    this.list = list;
  }

  private List<DataBean> list;

  public MyAdapter(Context context, List<DataBean> list) {
    this.context = context;
    this.list = list;
  }

  @Override
  public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    MyViewHolder viewHolder = new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false));
    return viewHolder;
  }

  @Override
  public void onBindViewHolder(MyViewHolder holder, final int position) {

    holder.tv_des.setText(list.get(position).name);
    holder.tv_des.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        DataBean bean = list.remove(position);
        notifyDataSetChanged();
        Toast.makeText(context,"删除了"+bean.name+"频道",Toast.LENGTH_SHORT).show();
      }
    });

    holder.tv_des.setOnLongClickListener(new View.OnLongClickListener() {
      @Override
      public boolean onLongClick(View v) {
        isShow = true;
        notifyDataSetChanged();
        return true;
      }
    });

    if (isShow) {
      holder.iv_icon.setVisibility(View.VISIBLE);
    } else {
      holder.iv_icon.setVisibility(View.GONE);
    }
  }

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

  @Override
  public void onMove(int currentPosition, int targetPosition) {

    Collections.swap(list, currentPosition, targetPosition);
    if (targetPosition < currentPosition) {
      List<DataBean> subList = list.subList(targetPosition + 1, currentPosition + 1);
      //向右移一位
      rightStepList(0, subList);
    } else {
      List<DataBean> subList = list.subList(currentPosition, targetPosition);
      //向左移一位
      leftStepList(0, subList);
    }
    notifyItemMoved(currentPosition, targetPosition);
  }
}

class MyViewHolder extends RecyclerView.ViewHolder {

  public ImageView iv_icon;
  public TextView tv_des;

  public MyViewHolder(View itemView) {
    super(itemView);
    iv_icon = (ImageView) itemView.findViewById(R.id.iv_icon);
    tv_des = (TextView) itemView.findViewById(R.id.tv_des);
  }
}

解释一下onMove方法,例如:我们的数据是[1,2,3,4,5,6],当6移动到3的位置时,那么数据源最后变化为[1,2,6,3,4,5]。但是在显示的时候我们先是将当前position和targetposition对调[1,2,6,4,5,3],然后取出[4,5,3]进行右移一位,这样数据源就对上了。如果是从3移动到6进行左移就可以了,数据排序的算法,采用反转的思想。

public class DataUtils {

  /**
   * 利用反转的思想对数据进行排序
   * 例如:list{0,1,2,3,4,5,6,7} 左移一位
   * 第一步:第一位先反转{0,1,2,3,4,5,6,7}
   * 第二部:剩下的在反转{0,7,6,5,4,3,2,1}
   * 第三步:全部反转{1,2,3,4,5,6,7,0}
   *
   * 例如:list{0,1,2,3,4,5,6,7} 右移一位
   * 第一步:最右边一位先反转{1,2,3,4,5,6,7}
   * 第二部:剩下的在反转{6,5,4,3,2,1,0,7}
   * 第三步:全部反转{7,6,5,4,3,2,1,0}
   *
   * 因为list的index是从0开始的,step要相应的-1
   * 优点:少创建对象,优化内存
   *
   * @param start
   * @param end
   * @param list
   */

  public static void reverseList(int start,int end,List list){

    int count = (end+1-start)/2 ;
    for(int i = 0;i< count;i++){
      Object temp = list.get(start+i);
      list.set(start+i,list.get(end-i));
      list.set(end-i,temp);
    }
  }
  public static void leftStepList(int step,List list){

    int size = list.size() -1;
    //左移
    reverseList(0,step,list);
    reverseList(step+1,size,list);
    reverseList(0,size,list);

  }

  public static void rightStepList(int step,List list){

    int size = list.size() -1;
    //右移
    reverseList(size-step,size,list);
    reverseList(0,size-step-1,list);
    reverseList(0,size,list);
  }
}

Activity布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:id="@+id/activity_channel"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context="com.iwintrue.channe.ChannelActivity">

  <android.support.v7.widget.RecyclerView
    android:id="@+id/rl_view"
    android:background="@color/white"
    android:layout_width="match_parent"
    android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>

</RelativeLayout>

子控件布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  >

  <RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="10dp">
    <TextView
      android:id="@+id/tv_des"
      android:layout_width="80dp"
      android:layout_height="30dp"
      android:text="屌丝男士"
      android:gravity="center"
      android:background="@drawable/rl_shape"
      android:textColor="@color/textColor"
      android:layout_marginTop="5dp"
      android:layout_marginRight="5dp" />
    <ImageView
      android:layout_alignRight="@+id/tv_des"
      android:layout_marginRight="-5dp"
      android:id="@+id/iv_icon"
      android:layout_width="20dp"
      android:layout_height="20dp"
      android:src="@mipmap/delete"
      android:scaleType="fitXY"
      android:visibility="gone" />

  </RelativeLayout>
</LinearLayout>

实现效果:

github地址:https://github.com/zhoukai1526/Channel

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android RecyclerView 复用错乱通用解法详解

    写在前面: 在上篇文章中说过对于像 RecyclerView 或者 ListView 等等此类在有限屏幕中展示大量内容的控件,复用的逻辑就是其核心的逻辑,而关于复用导致最常见的 bug 就是复用错乱.在大上周我就遇到了一个很奇怪的问题,这也是我下决心研究 RecyclerView 的原因. RecyclerView 源码分析 而这篇文章的目的首先是讨论在 RecyclerView 复用错乱时,一些通用的解决思路,其次就是探究我遇到的那个奇怪的问题,帮助未来同样遇到的朋友们. 复用错乱的解决办法

  • Android中RecyclerView的item宽高问题详解

    前言 本文主要给大家介绍了关于Android中RecyclerView的item宽高问题的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 在创建viewholder传入的View时,如果不指定其viewgroup,就会出现宽高只包裹显示内容的问题. View view = LayoutInflater.from(context).inflate(R.layout.test_test,null); 上面的做法就会出问题 改成这样就可以正常显示设置的宽高 View vie

  • Android利用RecyclerView编写聊天界面

    本文实例为大家分享了Android RecyclerView编写聊天界面的具体代码,供大家参考,具体内容如下 1.待会儿会用到RecyclerView,首先在app/build.gradle(注意有两个build.gradle,选择app下的那个)当中添加依赖库,如下: dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:24.2.1'

  • Android单个RecyclerView实现列表嵌套的效果

    很多时候会遇到一种需求,列表里面有列表,像这种需求之前一般都是用多个列表控件互相嵌套来实现,但是这样很容易出现一些问题,例如滚动冲突.数据显示不全.多余的逻辑处理等.后来发现,一个recyclerview就可以实现列表嵌套的效果,这里需要用到recyclerview的多布局功能. 效果图: recyclerview的多布局涉及到的主要方法是getItemViewType,作用是设置每个item要显示的布局类型.之前不了解的时候,都是直接用数学逻辑直接去计算,多少个position后显示什么布局,

  • Android中RecyclerView实现Item添加和删除的代码示例

    本文介绍了Android中RecyclerView实现Item添加和删除的代码示例,分享给大家,具体如下: 先上效果图: RecyclerView简介: RecyclerView用以下两种方式简化了数据的展示和处理: 1. 使用LayoutManager来确定每一个item的排列方式. 2. 为增加和删除项目提供默认的动画效果,也可以自定义. RecyclerView项目结构如下: Adapter:使用RecyclerView之前,你需要一个继承自RecyclerView.Adapter的适配器

  • Android RecyclerView 实现快速滚动的示例代码

    简评:Android Support Library 26 中终于实现了一个等待已久的功能: RecyclerView 的快速滚动 . Android 官方早就在建议开发者使用 RecyclerView 替代 ListView,RecyclerView 也确实表现要好于 ListView,除了没有快速滚动,就像下面这样: 因此,之前要想在 RecyclerView 上实现快速滚动,往往是依赖第三方库,比如:FutureMind/recycler-fast-scroll或 timusus/Recy

  • Android RecyclerView设置下拉刷新的实现方法

    Android RecyclerView设置下拉刷新的实现方法 1 集成 SwipeRefreshLayout 1.1 xml布局文件中使用 <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/refresh" android:layout_width = "match_parent" android:layout_height = "match_parent" &g

  • Android使用RecyclerView实现今日头条频道管理功能

    使用过今日头条的伙计们对这个效果肯定很熟悉.拖拽可排序,点击标签后可以删除.今天我们采用RecyclerView来实现. 实现思路: 通过ItemTouchHelper来绑定RecyclerView的子控件触摸事件. 当滑动拖拽的时候,通知适配器来交换两个子控件的显示位置. 更改数据源,使数据源与子空间显示内容一致. 这就是实现的基本思路,是不是很简单?当然,首先要了解一下ItemTouchHelper这哥们儿是干啥的,有什么作用. This is a utility class to add

  • Android RecyclerView仿新闻头条的频道管理功能

    需要在build里添加依赖 compile 'com.android.support:recyclerview-v7:25.3.1' 布局文件activity_main <android.support.v7.widget.RecyclerView android:layout_weight="1" android:id="@+id/recyclerView_up" android:layout_width="match_parent" a

  • Android实现仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中

    我这里只是简单的用了两个listview来实现的,先上效果图.比较粗糙.预留了自定义的空间. 思路: 从上图应该可以看的出来.就是上下两个listview.点击下面的ltem.会动态的移动到上一个listview的最后.上面的listview 为listview1,下面的为listview2. 点击listview2,获取到view ,设置一个动画,移动到listview1 ,listview2中删除被点的item.listview1中新增一个. 上代码: Mainactivity.java 部

  • Android中RecyclerView拖拽、侧删功能的实现代码

    废话不多说,下面展示一下效果. 这是GridView主文件实现. public class GridViewActivity extends AppCompatActivity { RecyclerView mRecyclerView; List<String> mStringList; RecyclerAdapter mRecyAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { s

  • android自定义view仿今日头条加载文字变色效果

    本文实例为大家分享了android自定义view加载文字变色效果的具体代码,供大家参考,具体内容如下 不分析了,很简单,直接贴代码: package com.loading; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import

  • Android应用中仿今日头条App制作ViewPager指示器

    一.概述 顶部ViewPager指示器的字体变色,该效果图是这样的: 大概是今天头条的app,神奇的地方就在于,切换ViewPager页面的时候,顶部指示器改成了字体颜色的变化,个人觉得还是不错的. 那么核心的地方就是做一个支持字体这样逐渐染色就可以了,我大概想了32s,扫描了一些可能实现的方案,最终定位了一个靠谱的,下面我就带大家开始实现的征程. 实现之前贴一下我们的效果图: 1.简单使用 效果如上图了,关于颜失色的改变我添加了两个方向,一个是左方向,一个是有方向. 单纯的使用,可能觉得没什么

  • Android实现今日头条订阅频道效果

    本文实例为大家分享了Android仿今日头条订阅频道,供大家参考,具体内容如下 源码:Android实现今日头条订阅频道 布局文件 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.andro

  • Android自定义gridView仿头条频道拖动管理功能

    项目中遇到这样个需求:app的功能导航需要可拖动排序,类似头条中的频道拖动管理.效果如下,gif不是很顺畅,真机会好很多. 虽然类似的文章网上搜一下有很多,但写的都不令人满意,注释不清晰,而且动画还不够流畅.经本人整理优化后,拿出来供后续有需要的使用. 实现原理: gridView作为基本控件 WindowManager.addView的方式实现可拖动的view TranslateAnimation实现移动动画,动画完后更新adapter即可 主要的实现原理上面已经说明,源码中关键的地点也有注释

  • Android仿今日头条滑动页面导航效果

    最近项目中用到了滑动页面,也就是和目前市场上很火的"今日头条"页面滑动类似,在网上找了一下,大部分都是用ViewPager来实现的,刚开始我用的是ViewPager+ViewGroup,上面的标题按钮用的是HorizontalScrollView,写完之后感觉效果比较生硬,果断换掉,发现了一个效果比较好的第三方,也就是今天的主题:PagerSlidingTabStrip.好了,下面来具体介绍一下PagerSlidingTabStrip,进行一下源码解析. 一.看一下demo的样子吧 二

  • Android 仿今日头条简单的刷新效果实例代码

    点击按钮,先自动进行下拉刷新,也可以手动刷新,刷新完后,最后就多一行数据.有四个选项卡. 前两天导师要求做一个给本科学生预定机房座位的app,出发点来自这里.做着做着遇到很多问题,都解决了.这个效果感觉还不错,整理一下. MainActivity package com.example.fragmentmytest; import android.content.DialogInterface; import android.graphics.Color; import android.os.B

随机推荐