android 2列移动,ClassifyView 基于可以拖拽 移动 合并 提取 的 GridView ,主要功能是提供 move 及 merge @codeKK Android开源站...

实现原理 ClassifyView 包裹这一个 RecyclerView,当点击这个 RecyclerView 会弹出一个 Dialog 该 Dialog 的布局会传入另一个 RecyclerView.想详细了解,~可以查看 博客~

效果如下

621953626ad658f9ef070f118294c91b.gif

4eb4bcf465a9966c244f9b823c37e8fe.gif

配置依赖

Step one: Add the JitPack repository to your build file

allprojects {

repositories {

...

maven { url "https://jitpack.io" }

}

}

Step two: Add the dependency

dependencies {

compile 'com.github.AlphaBoom:ClassifyView:$LATEST_VERSION'

}

最近更新

[x] 关于仿照 IReader 的效果需要对原库做自定义的部分都已经更新在 Sample

[x] 在 adapter 中增加了拖拽开始及拖拽开始完成和次级目录弹出的回调

[x] 增加拖拽 item 的可在拖拽时放大及可合并时缩小的设置

[x] 在拖拽开始时添加动画,效果更自然

[x] 添加了一个自定义的例子,效果大致仿 IReader 的书架

快速使用

继承 SimpleAdapter

public class MyAdapter extends SimpleAdapter {

public MyAdapter(List> mData) {

super(mData);

}

@Override

protected ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);

return new MyAdapter.ViewHolder(view);

}

//convertView 是缓存的 View 如何使用这个 convertView 参考 ListView 的使用步骤

@Override

public View getView(ViewGroup parent, View convertView, int mainPosition, int subPosition) {

//返回的 View 作为每一个 Item 的布局

/*布局内容自定义 例子中如下:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@drawable/round_shape"/>

*/

if (convertView == null) {

convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_inner, parent, false);

}

return convertView;

}

@Override

protected void onItemClick(View view, int parentIndex, int index) {

Toast.makeText(view.getContext(),"parentIndex: "+parentIndex+"\nindex: "+index,Toast.LENGTH_SHORT).show();

}

static class ViewHolder extends SimpleAdapter.ViewHolder {

public ViewHolder(View itemView) {

super(itemView);

}

}

}

2.找到 ClassifyView 并设置 Adapter

mClassifyView = (ClassifyView) view.findViewById(R.id.classify_view);

List> data = new ArrayList<>();

for(int i=0;i<30;i++){

List inner = new ArrayList<>();

if(i>10) {

int c = (int) (Math.random() * 15+1);

for(int j=0;j

inner.add(new Bean());

}

}else {

inner.add(new Bean());

}

data.add(inner);

}

mClassifyView.setAdapter(new MyAdapter(data));

添加拖动状态监听

设置监听

//添加监听

ClassifyView#addDragListener(DragListener)

//移除监听

ClassifyView#removeDragListener(DragListener)

//移除所有监听

ClassifyView#removeAllDragListener()

/**

* 是否监听移动状态信息

* @param enable false disable true enable default true

*/

ClassifyView#enableMoveListener(boolean)

具体监听回调

public interface DragListener {

/**

* 开始拖拽

*

* @param parent parent is ClassifyView

* @param startX start touch x relative classify view

* @param startY start touch y relative classify view

* @param region start drag region either main or sub

*/

void onDragStart(ViewGroup parent,View selectedView, float startX, float startY,@Region int region);

/**

* star drag animation end

* @param parent

* @param selectedView

* @param region

*/

void onDragStartAnimationEnd(ViewGroup parent,View selectedView,int region);

/**

* 拖拽结束(recover animation end)

*/

void onDragEnd(ViewGroup parent,@Region int region);

/**

* 释放被拖拽的 View

*/

void onDragRelease(ViewGroup parent, float releaseX, float releaseY,@Region int region);

/**

* move callback by touch location

*

* @param touchX 触摸的 X 坐标

* @param touchY 触摸的 Y 坐标

*/

void onMove(ViewGroup parent, float touchX, float touchY,@Region int region);

}

支持的自定义的属性

ClassifyView attr

属性

说明

MainSpanCount

主层级目录的列数

SubSpanCount

次级层级目录的列数

AnimationDuration

合并动画的时间

SubRatio

次级目录的高度占主层级的高度比例

EdgeWidth

设置宽度用于当 item 到边缘时判断是否触发滑动

MainPadding

设置主层级容器的 padding 值

MainPaddingLeft

MainPaddingTop

MainPaddingRight

MainPaddingBottom

SubPadding

设置次级层级容器的 padding 值

SubPaddingLeft

SubPaddingTop

SubPaddingRight

SubPaddingBottom

DragScaleX

当 item 处于被拖拽状态时 X 轴方向缩放比例

DragScaleY

当 item 处于被拖拽状态时 Y 轴方向缩放比例

DragInMergeScaleX

当被拖拽的 item 处于可合并状态时 X 轴方向缩放比例

DragInMergeScaleY

当被拖拽的 item 处于可合并状态时 Y 轴方向缩放比例

InsertAbleGridView(显示合并布局的 View)

属性

说明

RowCount

行数(默认 2)

ColumnCount

列数(默认 2)

RowGap

横向每列中的间隙距离

ColumnGap

纵向每行之间的间隙距离

OutLinePadding

处于可以合并状态及非合并状态 外围框的距离

OutlineWidth

外边框的宽度

OutlineColor

外边框的颜色

InnerPadding

当内部有多个子 View 时 与周围的边距

高级自定义

如果不喜欢List>的结构可以集成 PrimitiveSimpleAdapter 来实现其他数据源的 adapter

关于如何继承 PrimitiveSimpleAdapter 可以参考IReaderAdapter,如果不能满足可以考虑分别继承BaseMainAdapter及BaseSubAdapter

继承 ClassifyView 重写以下方法:

RecyclerView getMain(Context context, AttributeSet parentAttrs)

返回主层级使用的 RecyclerView。

RecyclerView getSub(Context context, AttributeSet parentAttrs) 返回次级层级使用的 RecyclerView

View chooseTarget(View selected, ListswapTargets, int curX, int curY)

当拖拽的 View 覆盖到子 View 时会通过该方法在候选 View 中选择一个 View 为目标 View 之后的交互操作都会作用于当前所选择的 View 及 这个目标 View

@param selected 当前选择的 View

@param swapTargets 候选的目标 View(候选的目标 View 为当前选择的 View 能够覆盖到所有 View)

@param curX 当前选中 View 的 X 轴坐标

@param curY 当前选中 View 的 Y 轴坐标

Drawable getDragDrawable(View view)

返回用于渲染当前拖动 View 的显示

@param view 当前选中的 View

@return drawable返回 Drawable 用于设置拖拽 View 的背景

自定义次级目录的布局:自定义次级目录的 Dialog:重写 Dialog createSubDialog()

自定义次级目录布局:重写 View getSubContent()

注意: 默认会在返回的 View 中查找有 Tag 为 @String/sub_container 的 View 作为容器 如果没有 就已返回的 View 作为容器来添加次级目录的 RecyclerView。 可以覆盖 ViewGroup findHaveSubTagContainer(ViewGroup group) 来重写查找容器的逻辑

设置数据方式有两种方式:

使用 ClassifyView.setAdapter(BaseMainAdapter mainAdapter, BaseSubAdapter subAdapter) 用于分别设置主层级及次级层级的适配器(使用这种方式只能获取到相应状态时的回调,注意这些回调返回值的处理)

使用 setAdapter(BaseSimpleAdapter baseSimpleAdapter) 设置一个混合了主层级及次级层级的适配器,如何自定义可以参考 SimpleAdapter

主层级提供的回调

在 BaseAdapter 中对于 mergeStart 等又增加了 ViewHolder 形式的回调 本质是一样的。

回调方法

说明

是否有默认实现在 BaseSubAdapter 中

setDragPosition

设置当前被拖拽的位置

true,默认效果为隐藏被拖拽的位置

boolean canDragOnLongPress

是否可以长按拖拽该 View

false

boolean canDropOVer

是否可以在对应点放下

true,默认返回 true

boolean onMergeStart

第一次处于可合并状态

false

void onMerged

合并结束

false

MergeInfo onPrepareMerge

当准备进行合并动画时回调,返回的 MergeInfo 用于做当前拖拽的 View 到目标位置的动画

false

void onStartMergeAnimation

开始合并动画的回调

false

void onMergeCancel

当脱离合并状态的回调

false

boolean onMove

当需要触发移动时的回调

false

void moved

移动完成的回调

false

boolean canMergeItem

能否进行合并操作

false

int onLeaveSubRegion

当从次级目录拖动出 item 到主层级时回调,返回 int 为添加到主层级 adapter 的位置

false

float getVelocity

只对低于这个速度的才判断能否移动(需要配合 getCurrentState)

true

int getCurrentState

判断当前处于的状态,返回三个值 Classify.STATE_NONE 无状态,Classify.STATE_MERGE 处于合并状态,Classify.STATE_MOVE 处于移动状态

true

void onItemClick

当 item 被点击时的回调

false

boolean canExplodeItem

用于判断当点击一个 item 时是否展开次级目录

false

次级层级的回调

次级层级与主层级相似 没有合并的相关回调:

方法

说明

void prepareExplodeItem

用于准备初始化次级层级数据

boolean canDropOver

对于次层级的 item 能否拖动到主层级

boolean canDragOut

是否可以移出次级目录到主层级

void onDialogShow

次级窗口显示时的回调

void onDialogCancel

次级窗口隐藏时的回调

结语

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值