Android 滑动事件与相册纵向滑动消失实现

Domo地址

项目地址https://github.com/kinglong123/FloatImages
draghelper分支:

图片.png

scroll 的使用

Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。而如果能够把Scroller的用法熟练掌握的话,我们自己也可以轻松实现出类似于ViewPager这样的功能。那么首先新建一个ScrollerTest项目,今天就让我们通过例子来学习一下吧。
先撇开Scroller类不谈,其实任何一个控件都是可以滚动的,因为在View类当中有scrollTo()和scrollBy()这两个方法。

对于scrollTo()和scrollBy()方法还有一点需要注意,这点也很重要,假如你给一个LinearLayout调用scrollTo()方法,并不是LinearLayout滚动,而是LinearLayout里面的内容进行滚动,比如你想对一个按钮进行滚动,直接用Button调用scrollTo()一定达不到你的需求,大家可以试一试,如果真要对某个按钮进行scrollTo()滚动的话,我们可以在Button外面包裹一层Layout,然后对Layout调用scrollTo()方法。
即:scrollTo()和scrollBy()方法特别注意:如果你给一个ViewGroup调用scrollTo()方法滚动的是ViewGroup里面的内容,如果想滚动一个ViewGroup则再给他嵌套一个外层,滚动外层即可。

scrollTo(int x, int y) x,y为正则向xy轴反方向移动,反之同理。

就是两个scroll方法中传入的参数,第一个参数x表示相对于当前位置横向移动的距离,

正值向左移动,负值向右移动

单位是像素。第二个参数y表示相对于当前位置纵向移动的距离,
正值向上移动,负值向下移动,单位是像素。

注意点:

1、即创建Scroller的实例,由于Scroller的实例只需创建一次,因此我们把它放到构造函数里面执行。另外在构建函数中我们还初始化的TouchSlop的值,这个值在后面将用于判断当前用户的操作是否是拖动。

2、接着重写onMeasure()方法和onLayout()方法,在onMeasure()方法中测量ScrollerLayout里的每一个子控件的大小,在onLayout()方法中为ScrollerLayout里的每一个子控件在水平方向上进行布局

3、接下来我们就该进行上述步骤中的第二步操作,调用startScroll()方法来初始化滚动数据并刷新界面。startScroll()方法接收四个参数,第一个参数是滚动开始时X的坐标,第二个参数是滚动开始时Y的坐标,第三个参数是横向滚动的距离,正值表示向左滚动,第四个参数是纵向滚动的距离,正值表示向上滚动。紧接着调用invalidate()方法来刷新界面。

4、在整个后续的平滑滚动过程中,computeScroll()方法是会一直被调用的,因此我们需要不断调用Scroller的computeScrollOffset()方法来进行判断滚动操作是否已经完成了,如果还没完成的话,那就继续调用scrollTo()方法,并把Scroller的curX和curY坐标传入,然后刷新界面从而完成平滑滚动的操作。

ViewDragHelper的使用

对于自定义ViewGroup而言这边的ViewDragHelper是一个很不错的实用程序类。它给我们提供一系列的方法和相关状态,让我们可以进行拖拽移动或者重新定位ViewGroup中子视图View。ViewDragHelper是一个简化View的拖拽操作的帮助类,使用起来比较简单与方便,一般我们只需要实现几个方法和一个CallBack类就可以实现拖动的View。

知识点:

1、ViewDragHelper 是一个工具类,为拖拽而生,它提供了一系列的方法和回调方法用来操纵拖拽及跟踪 child 被拖拽时的位置、状态。
2、回调方法 tryCaptureView() 返回值为 true 时,ViewDragHelper 才能拖动对应的 child。但是可以直接调用 captureChildView() 方法来指定被拖动的 child。
3、ViewDragHelper 要在 ViewGroup 中的 onInterceptTouchEvent() 方法中调用 shouldInterceptTouchEvent() 方法,然后在 ViewGroup 中的 onTouchEvent() 方法调用 processTouchEvent()。
4、ViewDragHelper 内部有一个 Scroller 变量,所以涉及到位移动画如 settleCapturedViewAt()、flingCapturedView()、smoothSlideViewTo() 方法时要复写 ViewGroup 的 computeScroll() 方法,在这个方法中调用 ViewDragHelper 的 continueSettling()。
5、如果要移动像 Button 这样 clickable == true 的控件,要复写 ViewDragHelper.Callback 中的两个回调方法 getViewHorizontalDragRange() 和 getViewVerticalDragRange(),使它们对应方法的返回值大于 0 就好了。

借助ViewDragHelper 实现相纵向滑动消失:

ss.gif

思路

今日头条使用了Activity,因为这个Activity可以显示前一个Activity,所以它一定是一个透明的Activity
这个用自定义的Activity主题就可以实现

用Android的Layout Inspector 工具查看今日头条它的布局,使用到ViewPager

1、定义FloatView继承LinearLayout
2、借助ViewDragHelper: mHelper = ViewDragHelper.create(this, 1f, new DragHelperCallback());
3、只拦截纵向滑动事件

    
 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        final int action = MotionEventCompat.getActionMasked(ev);
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            mHelper.cancel();
            return false;
        }
        final float x = ev.getX();
        final float y = ev.getY();
        boolean interceptTap = false;
        switch (action) {
            case MotionEvent.ACTION_DOWN: {
                mInitialMotionX = x;
                mInitialMotionY = y;
              //  interceptTap = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                final float adx = Math.abs(x - mInitialMotionX);
                final float ady = Math.abs(y - mInitialMotionY);
                final int slop = mHelper.getTouchSlop();
                /*useless*/
                if (adx > ady) {
                    mHelper.cancel();
                    return false;
                }
            }
        }
        return mHelper.shouldInterceptTouchEvent(ev) ;
    }
   

4、重写onViewReleased方法,根据位置做出滑动。滑动没有超过一半,回到原位,超过直接划出

       @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel)
        {
          
            final int childWidth = getHeight()/2;
            float offset = (releasedChild.getTop()) * 1.0f / childWidth;
            if(yvel>0 &&  offset >0){
                mHelper.settleCapturedViewAt((int)mDragOriLeft, getHeight());
            }
            else if(yvel >= 0 && offset > 0.5f){

                mHelper.settleCapturedViewAt((int)mDragOriLeft, getHeight());
            }
            else if(yvel<0 &&  offset <0){
             
                mHelper.settleCapturedViewAt((int)mDragOriLeft, -getHeight());
            }
            else if(yvel<=0  && offset < -0.5f){
           
                mHelper.settleCapturedViewAt((int)mDragOriLeft, -getHeight());
            }
            else{
                mHelper.settleCapturedViewAt((int)mDragOriLeft,(int)mDragOriTop);
            }

            invalidate();
        }

5、重写computeScroll

    @Override
    public void computeScroll()
    {

        if (mHelper != null && mHelper.continueSettling(true)) {

            invalidate();
        }else {

            if(Math.abs(mDragOffset) > 0.8 & mPositionListener!=null){
                mPositionListener.onFlingOutFinish();  //滑出回调

            }
        }
    }

6、使用:
ViewPager 放入FloatView布局中

    <com.lijian.FloatImage.FloatView
        android:layout_width="match_parent"

        android:id="@+id/fv"
        android:orientation="vertical"
        android:layout_height="match_parent" >
    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    </com.lijian.FloatImage.FloatView>
      floatView.setPositionListener(new FloatView.OnPositionChangeListener() {
            @Override
            public void onPositionChange(int initTop, int nowTop, float ratio) {
                if(ratio <0.05){
                    ratio = 0;
                }
                float alpha = 1 - Math.min(1, ratio * 5);
                mYfBottomLayout.setAlpha(alpha);
                mYfTitleLayout.setAlpha(alpha);
                mBackground.setAlpha(Math.max(0, 1 - ratio));//透明度设置
            }

            @Override
            public void onFlingOutFinish() {
                finish();//划出直接关闭activity
            }
        });

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271

推荐阅读更多精彩内容