仿探探卡片的实现

RecyclerView 是最佳选择!

第一,RecyclerView 是自带 Item View 回收和重用功能的,就不需要我们考虑这个问题了;

第二,RecyclerView 的布局方式是通过设置 LayoutManager 来实现的,这样就充分地把布局和 RecyclerView “解耦”开来了。而 LayoutManager 是可以通过自定义的方式来实现的。这恰恰是我们想要的(实现卡片层叠式)!!!

下面详细说一下:

1. RecyclerView属于新增的控件,Android将RecyclerView定义在support库里。若要使用RecyclerView,第一步是要在build.gradle中添加对应的依赖库。

app/build.gradle中的dependencies闭包添加以下内容:

 

    implementation 'com.android.support:recyclerview-v7:27.1.1'

由于RecyclerView不是内置在系统SDK中,需要把其完整的包名路径写出来

<android.support.v7.widget.RecyclerView

2. 然后,每一个item,都要有一个类(java类文件)card.java和一个布局文件(card.xml),类中保存界面中的数据。

3. 新增适配器CardAdapter.java,里面有数据集合list,是activity传过来的,在adapter里定义了一个viewholder类,在它的构造函数中实现卡片上控件的获取,因为传入了一个view,就是用这个view实现的。这个viewholder的初始化在于adapter 重载了oncreateviewholder函数,返回这个holder就行。而view也就是在这时候直接获取的R.

4.如何与数据绑定呢?这里adapter重载了onBindViewHolder(ViewHolder holder, int position),在这里就可以实现与特定的数据设置了,例如

Fruit fruit = mFruitList.get(position);
holder.fruitImage.setImageResource(fruit.getImageId());
holder.fruitName.setText(fruit.getName());

至此recyclerview设置完毕了。在哪里设置监听呢?在adapter里设置关于item的点击监听。

3. 那么如何实现滑动效果呢?卡片里是一个layout,卡片是如何排列的是另一种layout。实际上,卡片如何排列的全靠用代码写出来的,创建 CardLayoutManager 并继承自 RecyclerView.LayoutManager,在这里实现实现重叠排列,显示多少个,以及后续添加的效果,然后用recyclerview绑定它就可以了。添加子卡片完全是用addview实现的,比较方便,实际上,list是时常变化的,究竟选择那一个单词,实际上应该是在这里单独出一个类,用来选择list。

4. 紧接着,可以拖动它的话,需要设置一个先定义一个监听器。主要用于监听卡片滑动事件,是一个interface,究竟是怎么用,看下面。

5. 用 ItemTouchHelper ,也是直接关联在控件上,而 ItemTouchHelper又关联了一个callback,在callback里面写触发函数,具体怎么回事呢,反正重写了函数,就会有拖动的效果。反正大致就这么样的,不同的功能,就添加到上面就可以了。

唉,算了,下面学习一下别的,但是今天真的没时间了。

itemDragListener是adapter里的一个变量,初始化的时候传进去了(是上下文。。。),adapter接了ItemMoveListener的接口

ItemTouchHelper是绑定在recyclerview上的,跟adapter差不多,本身activity里面就有一个private ItemTouchHelper mItemTouchHelper;是下面用的。

在adapter里有private ItemDragListener mItemDragListener;在里面也并没有发现有关于什么的代码。

反正添加代码就那么个意思,容易了。

看来还得实现自己的布局。

从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。没有任何实现代码。接口中所有的方法,都是抽象方法,抽象方法是用abstract定义的,但interface不用,它本来就是。接口中除了定义方法外,还可以定义成员变量,方法和属性默认都是public修饰,也可以使用protected,但不能用private ,所有的属性都是静态的常量,默认省略了static和final修饰符,属性的值必须实例化(初始化)。

在JAVA中,一个类无法继承自多个类,但是可以实现多个接口,使用关键字implements 多个接口之间使用“,”隔开 多个接口之间,没有先后顺序。 

各种监听器listener比较喜欢用interface,里面的函数是on什么什么。本身activity继承了ItemDragListener,实现了onStartDrags,里面调用了mItemTouchHelper.startDrag(viewHolder);

adapter继承了ItemMoveListener,它的功能是侧滑删除和拖动交换位置。它用MyItemTouchHelperCallback实现初始化,这个类继承自ItemTouchHelper.Callback,里面决定了左右拖动或交换位置的具体代码。只要把这个helper给.attachToRecyclerView(recyclerView);就可以了。

不简单的是,这个callback里有一个ItemMoveListener的属性,该属性恰好是adapter继承的,因此填入了adapter。因为这个callback里面有onmove和onswipe,这里才是真正的系统调用,这时调用adapter里面的onitemmove什么的,因为adapter里面正好有数据,可以删除。因此,itemmovelistener是用来操作每一个项的。比较巧妙。

那么,不要这个抽象接口行不行呢?首先,item的move和swipe的触发是在helper的callback首先传进来的,因此callback完全可以用adapter的类实现而不用接口,毕竟接口只是实现通用性的工具。

但是从另外一个角度来说,callback里面的属性是mItemMoveListener,而不是adapter,毕竟也用不到adapter其他的函数,因此这样更清晰了。因此不要改为妙。

重新总结一下:

activity里声明了mItemTouchHelper

adapter里继承了ItemMoveListener

ItemTouchHelper的callback声明了ItemMoveListener,也就是adapter

然后callback用adapter初始化,ItemTouchHelper用callback初始化,然后再关联到recyclerview上,完成。

接下来看看drag listener,前面说到,是activity实现了这个接口,而实现的onStartDrags里只调用了mItemTouchHelper.startDrag(viewHolder);,如果你想自定义触摸view,那么就使用startDrag(ViewHolder)方法。

adapter中声明了一个mItemDragListener,好乱啊。。。在初始化的时候就用activity传入了。在继承的onBindViewHolder函数中使用了

public void onBindViewHolder(final ViewHolder holder, int position) {
    RecyclerItem recyclerItem = mList.get(position); // 刚绑定的时候,设置数据
    holder.textView.setText(recyclerItem.getText());
    holder.textView.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            mItemDragListener.onStartDrags(holder);
            return false;
        }
    });
}

可以看到,viewholder就是一个item的UI,在这里实现UI与数据的绑定,当然,还有点击函数的绑定。因此在这里使用了mItemDragListener.onStartDrags(holder);,转而执行activity的onStartDrags,进而执行mItemTouchHelper.startDrag(viewHolder);,说过了,如果你想自定义触摸view,那么就使用startDrag(ViewHolder)方法。现在的这个holder明显是整个item。可能说,传进去之后,就会传出一个onmove,在这个onmove里面实现list的删除,就是这样的。上面写着为图形拖动做准备。

成功了,然后卡片的大小,阴影,颜色,都是自己设定的。实现阴影,圆角,都是通过引用xml文件显示出来的,后面再做吧。

对,先做阴影什么的

设定圆角矩形,需要在res里面加上Android resourse file即可。

类似的例如这样:

<shape xmlns:android="http://schemas.android.com/apk/res/android">
  <solid android:color="#ffffff" />
   <stroke android:color="#20000000" android:width="1dp"/>
    <corners
        android:bottomLeftRadius="10dp"
        android:bottomRightRadius="10dp"
        android:topLeftRadius="10dp"
        android:topRightRadius="10dp" />
</shape>

其中corners 中定义每边的圆角弧度。

solid为填充的颜色:半透明颜色:#10000000~#90000000 透明深度不一样。指定内部填充色

gradient:用以定义渐变色,可以定义两色渐变和三色渐变,及渐变样式

stroke:描边属性,可以定义描边的宽度,颜色,虚实线等

size:定义图形的大小

在这里

https://www.jianshu.com/p/b65e489093c7

在background引用即可。

 

突然感觉好乱啊。。。首先说,callback是一个类,它不是接口,也不会继承。它里面调用了list和adapter,但是callback里面怎么可能有?

mItemTouchHelper在CardLayoutManager就有。但是实际上没有用到它。
OnSwipeListener也就是在adapter里用了一下。

说实话,到现在这里已经完全乱了。

不管怎么样,现在成功了。。。

现在没有回调监听,下面的有些不成功。

感觉不错,但是现在已经完全OK了。

那你首先应该知道,这三个接口:DragListener,MoveListener和Swipe Listener各自有什么作用。

DragListener:

void onStartDrags(RecyclerView.ViewHolder viewHolder);

里面调用了ItemTouchHelper的startDrag(viewHolder)方法可以手动开启拖动效果,用来开启拖动动画(当拖动时)。

CardMoveListener:
boolean onItemMove(int fromPosition, int toPosition);
boolean onItemRemove(RecyclerView.ViewHolder viewHolder);

看来实现了card的拖动与移出监听。

public interface OnSwipeListener<T> 
    void onSwiping(RecyclerView.ViewHolder viewHolder, float ratio, int direction);卡片还在滑动时回调
    void onSwiped(RecyclerView.ViewHolder viewHolder, T t, int direction);卡片完全滑出时回调
    void onSwipedClear();所有的卡片全部滑出时回调

看来实现了卡片在各个状态时的回调,用于复位,删除等。大概就是利用DragListener开启拖动效果,然后用Swipe Listener监听各种状态,最后用CardMoveListener实现删除。

因此,Drag可以直接不用了。。。然后猜测利用swip触发函数实现的move触发。

那到底谁用了swipelistener呢?感觉没人用啊。。。

现在基本上都成功了。。。但是现在还没搞明白。

再串通一遍。它之所以用接口是为什么呢,是因为几个类之间需要相互调用,adapter就是处理数据的地方,callback就是监听的地方,在监听的地方调用adapter的数据处理函数,就是这样的,根本用不了接口。

但是从另一个角度说来,on什么什么是别人调用的,自己实现内容即可,对吧。怎么个设计方法呢?

怎么说呢,这接口就这样吧。名字还是很直白的。

那么adapter是主管数据的,那么helper和layout分别管什么呢?

其实layout掌管着显示和排列。在helper里判定滑动到哪里算是可以过去。在callback的固有继承的函数里去调用了几个on回调。

在onChildDraw上实现了判定。

因此感觉监听器意义不大了,毕竟没有谁用这个swipe接口,删掉吧,一点意义也没有了。

不是,它是用来判断是左划还是右划什么的,还是划完了,这些状态还是蛮重要的,继承给谁呢?继承给主activity就可以显示弹窗了是不是。它的作用是这个。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值