Android手把手教你實(shí)現(xiàn)滑動隱藏(GeastureDetector使用)

因?yàn)橐苿釉O(shè)備有限的顯示屏幕,很多時候都需要在合適的時間去隱藏一些控件,比如滑動隱藏就是一個好的設(shè)計(jì)方案。本文將實(shí)現(xiàn)一個通用性較強(qiáng)的滑動隱藏方案,順便采用了GeastureDetector這個好用的用戶動作檢查工具。

一、本文擬實(shí)現(xiàn)的效果圖

最近下載了Now直播APP,發(fā)現(xiàn)它實(shí)現(xiàn)了一個比較流暢的滑動隱藏效果,具體看下面的GIF圖。

image

因?yàn)樵诶习姹镜哪M器上運(yùn)行,顯得有點(diǎn)卡頓,這不是主要的。界面中有一個綠色的功能按鈕,隨著ListView上滑,它就向下滑動隱藏。能夠看出來它同時還包括了一個變透明的效果。本文將模仿實(shí)現(xiàn)一個這樣的滑動隱藏效果,還是按我的老套路,先上最后的效果圖。

image

二、具體實(shí)現(xiàn)。

1. 布局文件,主要是一個ScrollView,里面包含了一個textView,另外就是一個功能按鈕。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <TextView
            android:id="@+id/textview1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:paddingBottom="1000dp"
            android:paddingTop="250dp"
            android:text="可滑動的ScrollView"
            />
    </ScrollView>
    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="20dp"
        android:text="功能滑動按鈕"
        />
</RelativeLayout>

2. MainActivity中的主體內(nèi)容,主要干了如下幾件事。

  • 其中給ScrollView添加了一個touch監(jiān)聽器
  • 處理用戶滑動事件采用了GestureDector
  • 初始化和獲取一些關(guān)鍵的成員變量

下面代碼中有一個小細(xì)節(jié),就是用了View.post()方法去獲取mButton的原始top值,為什么要這么干呢?

讀者可以試一試直接獲取,這時候你調(diào)試發(fā)現(xiàn)獲取的值是0;

因?yàn)樵趏nCreate的時候,view的繪制可能還沒有完成,采取view.post()的方法可以解決這個問題。

package com.example.administrator.myapplication;

import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;

public class MainActivity extends AppCompatActivity {

    private GestureDetectorCompat mDetectorCompat;
    private Button mButton;
    private ScrollView mScrollView;
    private int mOriginButtonTop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mButton = (Button) findViewById(R.id.button2);

        mButton.post(new Runnable() {//post一個線程去獲取button的原始top值
            @Override
            public void run() {
                mOriginButtonTop = mButton.getTop();
            }
        });

        mScrollView = (ScrollView) findViewById(R.id.scrollView);
        mDetectorCompat = new GestureDetectorCompat(this, new MyGestureListener());

        mScrollView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mDetectorCompat.onTouchEvent(event);
                return false;
            }
        });
    }
}

3. 第2步中的MyGestureListener 的實(shí)現(xiàn)。

使用GeastrueDetector必須要傳入一個具體的監(jiān)聽器實(shí)現(xiàn),這個很好理解,因此繼承了GestureDetector.SimpleOnGestureListener來實(shí)現(xiàn)具體的滑動處理邏輯,在它的onScroll()方法中主要干了如下幾件事:

  • 首先判斷是不是豎直方向的滑動
  • 判斷是向上滑動還是向下滑動
  • 根據(jù)不同的滑動方向動態(tài)改變功能按鈕的top和bottom的值,實(shí)現(xiàn)一個移動的效果。
  • 因?yàn)槭腔瑒佣嗌倬鸵苿佣嗌伲赃@個效果的連續(xù)性和流暢性還是不錯的。
  • 最后注意一些限制,功能按鈕不能向上滑出原本的邊界;向下移動,如果離開了屏幕的可見范圍,就不再移動它。
 class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

            if (Math.abs(distanceY) > Math.abs(distanceX)) {//判斷是否豎直滑動
                int buttonTop = mButton.getTop();
                int buttonBottom = mButton.getBottom();

                //是否向下滑動
                boolean isScrollDown = e1.getRawY() < e2.getRawY() ? true : false;

                //根據(jù)滑動方向和mButton當(dāng)前的位置判斷是否需要移動Button的位置
                if (!ifNeedScroll(isScrollDown)) return false;

                if (isScrollDown) {
                    //下滑上移Button
                    mButton.setTop(buttonTop - (int) Math.abs(distanceY));
                    mButton.setBottom(buttonBottom - (int) Math.abs(distanceY));
                } else if (!isScrollDown) {
                    //上滑下移Button
                    mButton.setTop(buttonTop + (int) Math.abs(distanceY));
                    mButton.setBottom(buttonBottom + (int) Math.abs(distanceY));
                }
            }

            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        //寫一個方法,根據(jù)滑動方向和mButton當(dāng)前的位置,判斷按鈕是否應(yīng)該繼續(xù)滑動
        private boolean ifNeedScroll(boolean isScrollDown) {
            int nowButtonTop = mButton.getTop();

            //button不能超出原來的上邊界
            if (isScrollDown && nowButtonTop <= mOriginButtonTop) return false;

            //判斷按鈕是否在屏幕范圍內(nèi),如果不在,則不需要再移動位置
            if (!isScrollDown) {
                return isInScreen(mButton);
            }

            return true;
        }

    }

4. 上一步中注意判斷View是否在屏幕可見范圍內(nèi)的一個方法。


        //判斷一個控件是否在屏幕范圍內(nèi)
    private boolean isInScreen(View view) {
            int width, height;
            Point p = new Point();
            getWindowManager().getDefaultDisplay().getSize(p);
            width = p.x;
            height = p.y;

            Rect rect = new Rect(0, 0, width, height);

            if (!view.getLocalVisibleRect(rect)) return false;

            return true;
        }

總結(jié)

最后運(yùn)行的效果圖,已經(jīng)在最前面展示過了。本文的滑動隱藏的原理實(shí)現(xiàn)的關(guān)鍵點(diǎn)有如下幾點(diǎn):

  • 滑動的隱藏的原理是移動需要隱藏的控件,直至滑出屏幕外。

  • 本文采取的移動方式是動態(tài)改變控件的top和bottom值,當(dāng)然還有別的方式,比如scrollBy(),setTranslateY(),setPadding(),但是他們有各自的應(yīng)用場景。比如scrollBy()實(shí)際上沒有移動View只是移動了View的內(nèi)容,如果你不希望引起其他View的位置變化,可以采用scrollBy()方法。

  • 本文通過在onScroll()方法里采取滑動多少距離就移動功能按鈕多少距離,保證功能按鈕移動的連續(xù)性,避免一個突兀跳變的問題。

  • 最后,就是注意滑動邊界的判斷,在上述步驟中已經(jīng)說明了。讀者可以不加滑動邊界判斷,試一試是什么效果。

ok,如果覺得本文幫到了你,請留言、點(diǎn)贊,和關(guān)注,期待和你一起進(jìn)步!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,366評論 25 708
  • 內(nèi)容是博主照著書敲出來的,博主碼字挺辛苦的,轉(zhuǎn)載請注明出處,后序內(nèi)容陸續(xù)會碼出。 當(dāng)了解了Android坐標(biāo)系和觸...
    Blankj閱讀 6,884評論 3 60
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,838評論 4 61
  • 孫悟空的五指山,五指山的符文 不能玩多余一把 2個小時有點(diǎn)多啊,上班才上8小時班,占比太重了
    mimikatz閱讀 181評論 0 0
  • 賀先生今天穿的黑色無帽衛(wèi)衣和白色內(nèi)襯,走路帶風(fēng),有點(diǎn)帥,我真幸福
    莫淮閱讀 237評論 0 0

友情鏈接更多精彩內(nèi)容