android rebound平移,Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout

Android 仿 IOS 拖拽回弹之进阶 ReboundFrameLayout

前言

IOS 拖拽回弹给用户的体验不得不赞然后 Android 原生的 API 各种不支持, 于是乎出现的很多仿 IOS 拖拽回弹的 Android 控件 ReboundScrollView, 比起原生的 ScrollView, 体验上好了很多, 但是还是不尽人意: RebounScrollView 里的内容超出屏幕时, 你想一次性在显示完 ScrollView 里的内容紧跟着拽出屏幕, 你发现你做不到, 臣妾也做不到! 于是乎, 我想我是不是可以试试? 下面分享一个让你也可以有 IOS 拖拽回弹般体验的 ReboundFrameLayout 既然 Android 原生的 ScrollView 做不到, 那我干脆舍弃不用, 我们自己做类似 ScrollView 的滑动, 这样方便我们在滑动到顶部 (或底部) 时可以继续向下(或向上滑动)

这里链接两个大神写的拖拽回弹控件:

1ReboundScrollView 仿 IOS 拖拽回弹

2 Android 上实现仿 IOS 弹性 ScrollView

我的思路

ab7653affab982b574eb7acc55df2e04.gif

思路图

效果展示

ab7653affab982b574eb7acc55df2e04.gifReboundFramLayout

实现

利用 Scroller 方式实现滚动

代码实现比较简单, 且有详细的注释ReboundFrameLayout.java

packagejsc.kit.org.rebound;

importandroid.content.Context;

importandroid.graphics.Rect;

importandroid.util.AttributeSet;

importandroid.view.MotionEvent;

importandroid.view.View;

importandroid.view.ViewConfiguration;

importandroid.widget.FrameLayout;

importandroid.widget.Scroller;

/**

* 布局上下反弹

*

* @author jsc

*/

publicclassReboundFrameLayoutextendsFrameLayout{

privatefinalStringTAG=getClass().getSimpleName();

privatefinalfloatRATIO=0.65f;

privatefinalintANIM_TIME=300;

privateViewmChildView;

privatefloatmCurY;

privatefloatmLastY;

privateScrollermScroller;

privateintmTouchSlop;

publicReboundFrameLayout(Contextcontext,AttributeSetattrs){

super(context,attrs);

mScroller=newScroller(context);

mTouchSlop=ViewConfiguration.get(context).getScaledPagingTouchSlop();

}

@Override

protectedvoidonFinishInflate(){

super.onFinishInflate();

mChildView=getChildAt(0);

}

@Override

publicbooleanonInterceptTouchEvent(MotionEventev){

switch(ev.getAction()){

caseMotionEvent.ACTION_DOWN:

mCurY=ev.getY();

mLastY=mCurY;

caseMotionEvent.ACTION_MOVE:

floatmCurY=ev.getY();

intmark=(int)(mCurY-mLastY);

intslop=Math.abs(mark);

mLastY=mCurY;

// 当滑动的距离小于 10px 的时候, 我们认为这次滑动是无效的, 销毁这次事件

if(slop>=10){

returntrue;

}

break;

caseMotionEvent.ACTION_UP:

break;

}

returnsuper.onInterceptTouchEvent(ev);

}

@Override

publicbooleanonTouchEvent(MotionEventev){

switch(ev.getAction()){

caseMotionEvent.ACTION_DOWN:

floatmCurY=ev.getY();

mLastY=mCurY;

caseMotionEvent.ACTION_MOVE:

mCurY=ev.getY();

intmYOffset=(int)((mCurY-mLastY)*RATIO);

scroll(mChildView,mYOffset);

mLastY=mCurY;

returntrue;

caseMotionEvent.ACTION_UP:

if(!mScroller.isFinished()){

mScroller.forceFinished(true);

}

mScroller.startScroll(0,getScrollY(),0,-getScrollY(),ANIM_TIME);

invalidate();

default:

break;

}

returntrue;

}

@Override

publicvoidcomputeScroll(){

if(mScroller.computeScrollOffset()){

scrollTo(mScroller.getCurrX(),mScroller.getCurrY());

postInvalidate();

}

}

privatevoidscroll(ViewmChildView,intmYOffset){

//child 内容下滑高度

intchildScrolledY=mChildView.getScrollY();

//child 在其 parent 中的可见部分

Rectrect=newRect();

mChildView.getLocalVisibleRect(rect);

//child 实际内容高度

mChildView.measure(0,0);

intrealHeight=mChildView.getMeasuredHeight();

//child 内容滑动到其 parent 底部时需要向上滑动的距离

intdistanceFromBottom=realHeight-rect.bottom;

if(mYOffset>0){// 向下滑动

// 如果向下滑动的距离小于 child 内容上滑到其 parent 顶部的距离, 则向下滑动 child 内容 mYOffset 距离

if(mYOffset

mChildView.scrollBy(0,-mYOffset);

}else{// 如果滑动的距离大于或等于 child 内容已经下滑的高度, 则向下滑动 child 的内容至其 parent 的顶部, 再向下滑动超出部分的距离

mChildView.scrollBy(0,-childScrolledY);

scrollBy(0,-(mYOffset-childScrolledY));

}

}elseif(mYOffset<0){// 向上滑动

intdistance=Math.abs(mYOffset);

// 如果向上滑动的距离小于 child 内容下滑到其 parent 底部的距离, 则向上滑动 child 内容 distance 距离

if(distance

mChildView.scrollBy(0,distance);

}else{

mChildView.scrollBy(0,distanceFromBottom);

scrollBy(0,distance-distanceFromBottom);

}

}

}

}

关键在于方法

scroll(View mChildView, int mYOffset)

里面的处理注释很详细, 请自行参阅

最后附上源码的下载地址: https://github.com/JustinRoom/JscKit/tree/master/rebound

来源: http://www.jianshu.com/p/53d13719a6c4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值