向左拖拽跳转至“更多页面”的通用控件 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
uin3566
V2EX    分享创造

向左拖拽跳转至“更多页面”的通用控件

  •  
  •   uin3566 2016-12-3 00:43:50 +08:00 2422 次点击
    这是一个创建于 3288 天前的主题,其中的信息可能已经有所发展或是发生改变。

    Github

    https://github.com/uin3566/DragFooterView

    效果图

    项目来源

    本项目来源于公司的项目需求,需要做成如下效果:

    这是某个 App 里面的效果,名字我就不说啦,不打免费广告,哈。 我发现市面上很多 app 都有这方面的需求,但基本上都是在右上角添加一个“更多”标签,然后点击“更多”跳转至另一个页面,类似于下面这样,此图来自豆瓣 App 。

    douban.png

    这种体验中规中矩,但我还是觉得向左拖拽比较。。于是就写下了本项目,为这种向左拖拽的交互方式提供一种通用的解决方案

    介绍

    作为一种 library ,怎么可以只有以上这一种效果呢。因此,可插拔的 Footer View是必须的。 下面是我定制的另外两种效果,当然,你也可以定制任意你想要的效果。

    上图中的字符串转 Path功能用的是秋百万大神的android-Ultra-Pull-To-Refresh下拉刷新库中的类StoreHousePath,只不过将字符串从横向改为了竖向,在此深表感谢,顺便膜拜下。

    涉及的知识点

    本质上说,这个控件是一个自定义的 ViewGroup,需要支持左滑,需要支持可插拔化的 Footer View ,所以View 的事件分发, View 的绘制这两个知识点都必须用到。 View 的绘制就不多说了,无非是 Canvas , Paint , Path 结合动画的用法,**GcsSloop 魔法师的文章讲解的又好逼格又高,推荐下,具体的绘制可以看我的代码,自以为写的还是蛮清晰的 e 。 这里看下事件分发,由于 DragContainer 支持放置了各种子 View ,比如 Button , RecyclerView , HorizontalScrollView 等。那么,有时候需要子控件响应事件,有时候需要 DragContainer 响应拖拽**。本项目通过重写 dispatchTouchEvent 实现需求,代码分析详见代码中的注释。

     @Override public boolean dispatchTouchEvent(MotionEvent event) { //若复位动画正在执行,则直接 return if (resetAnimator != null && resetAnimator.isRunning()) { return super.dispatchTouchEvent(event); } //调用 ViewGroup 的 dispatchTouchEvent 方法,将 //事件分发给子 View 。 super.dispatchTouchEvent(event); //调用 IDragChecker 接口的 canDrag 方法判断此时 DragContainer //的可拖拽状态,本项目提供了默认实现类 DefaultDragChecker //将根据子 View 的类型来返回一个 boolean 。若返回 false , //则该方法直接返回,返回 true 才能执行后续的拖拽操作。 //以 RecyclerView 为例,若 RecyclerView 没有滑动到最底部 //则返回 false ,否则返回 true , DragContainer 将会对后续事件 //进行处理。 if (!dragChecker.canDrag(contentView)) { return true; } //DragContainer 处理拖拽事件 switch (event.getAction()) { case MotionEvent.ACTION_DOWN: dragDx = 0; downX = event.getX(); downY = event.getY(); lastMoveX = downX; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(event.getX() - downX); float dy = Math.abs(event.getY() - downY); //dx >= dy 时判定为横向拖动,不允许 parentViewGroup //拦截事件,否则使之拦截事件。 if (dx >= dy) { getParent().requestDisallowInterceptTouchEvent(true); } else { getParent().requestDisallowInterceptTouchEvent(false); } //若此时往左拖动,则开始处理 ACTION_MOVE 事件 if (dragDx <= 0 && dragChecker.canDrag(contentView)) { //这里更新拖拽状态, Footer View 的绘制依赖于该状态 //该函数判断此时是往左拖拽还是往右拖拽。 updateDragState(event); if (dragDx != 0) { //拖拽时发送 ACTION_CANCEL 给子 View ,取消 View 的事件序列,否则 View 将与 DragContainer 产生事件冲突。 sendCancelEvent(event); } dragDx = event.getX() - downX; //dragDamp 是拖拽阻尼,取值范围是(0,1]。值越小,阻尼越大 float realDragDistance = dragDx * dragDamp; //更新子 View 的位置。 setContentView((int) realDragDistance, 0, containerWidth + (int) realDragDistance, containerHeight); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: //手指抬起时或接收到 ACTION_CANCEL 时子 View 恢复原位。 resetContentView(); break; } return true; } 

    用法

    1 、添加依赖

    • step1:Add it in your root build.gradle at the end of repositories:
     allprojects { repositories { ... maven { url "https://jitpack.io" } } } 
    • step2:Add the dependency:
     dependencies { compile 'com.github.uin3566:DragFooterView:v1.0.2' } 

    2 、在 xml 中配置如下 (注意: DragContainer 只能有一个子 View)

     <com.fangxu.library.DragContainer android:id="@+id/drag_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dp"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/white" /> </com.fangxu.library.DragContainer> 

    3 、在 java 类中添加事件监听器 DragListener

     DragContainer dragCOntainer= (DragContainer) findViewById(R.id.drag_image_view); //若需使用自己定制的 footer ,需要调用 DragContainer 的 setFooterDrawer 方法设置定制的 footer 类,如下 //其中 ArrowPathFooterDrawer 继承于 BaseFooterDrawer dragContainer.setFooterDrawer(new ArrowPathFooterDrawer.Builder(this, 0xff444444).setPathColor(0xffffffff).build()); dragContainer.setDragListener(new DragListener() { @Override public void onDragEvent() { //do whatever you want,for example skip to the load more Activity. Intent intent = new Intent(HomeActivity.this, ShowMoreActivity.class); startActivity(intent); } }); 

    可自定义属性

    |attribute|value type|defalut value| description| | --- | --- | --- | --- | |dc_footer_color|color|0xffcdcdcd|footer view 的背景颜色| |dc_reset_animator_duration|integer|700|松开拖拽后复位动画的时长| |dc_drag_damp|float|0.5f|拖拽阻尼系数,取值在(0,1]之间,取值越小,阻尼越大|
    其余 footer view 的属性参数交给 BaseFooterDrawer 的实现类自己设置。

    小结

    木有小结,我就是来打广告的,哈哈,如果你觉得本项目对你的学习有帮助,具有一定的实用价值,那就多多 star ,多多 follow 吧! 最后再厚颜无耻地再贴一次 github 地址: https://github.com/uin3566/DragFooterView

    目前尚无回复
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     933 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 20:27 PVG 04:27 LAX 12:27 JFK 15:27
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86