1. 程式人生 > >Android 實現View滑動幾種方式

Android 實現View滑動幾種方式

關於View的滑動,Android中提供了許多方法,具體可以分為一下幾類:

layout

在ACTION_MOVE中通過獲取x、y的偏移量動態佈局view,並禁止向父控制元件傳遞事件:

@Override
    public boolean onTouchEvent(MotionEvent event) {

        int x = (int) event.getX();
        int y = (int) event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                break
; case MotionEvent.ACTION_MOVE: int offsetX = x - mLastX; int offsetY = y - mLastY; layout( getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY ); break
; } return true; }

offsetLeftAndRight和offsetTopAndBottom

將上述layout方法改為該兩個方法的組合,偏移量計算同上:

 case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;

                offsetLeftAndRight(offsetX);
                offsetTopAndBottom(offsetY);
                break
;

LayoutParams

實現方法和layout相似,動態設定佈局引數,缺點是如果view引數加了rules,會導致無法滑動:

    case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;

                ViewGroup.MarginLayoutParams params
                        = (ViewGroup.MarginLayoutParams) getLayoutParams();

                params.leftMargin = getLeft() + offsetX;
                params.topMargin = getTop() + offsetY;

                setLayoutParams(params);
                break;

ScrollBy

scrollBy移動的是view中的內容或者ViewGroup中的所有子view,故需先獲得父控制元件的例項;同時scrollBy引數的正負是和android座標軸的正負方向相反的,故需隊offset值取反:

 case MotionEvent.ACTION_MOVE:
                int offsetX = x - mLastX;
                int offsetY = y - mLastY;

                ((View) getParent()).scrollBy(-offsetX, -offsetY);
                break;

ViewDragHelper

該類非常強大,基本可以各種不同的滑動、拖放需求。support庫中DragLayout也是基於此類實現側滑效果。使用該類一般需要如下幾個步驟:

  • 繼承自ViewGroup,在構造中初始化ViewDragHelper物件,傳入的兩個引數分別為當前容器物件和ViewDragHelper中的回撥介面,該回調中封裝了子view的滑動操作相關api
    public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mViewDragHelper = ViewDragHelper.create(this, mCallBack);
    }
  • 觸控事件攔截與處理,需要將事件傳遞給ViewDragHelper處理
 @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }
  • 處理ViewDragHelper中回撥Callback
private ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback() {

        /**
         * 指定可以滑動的子View,比如當前只有mMainView可以滑動
         * @param child
         * @param pointerId
         * @return true 指定的子view可以滑動
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mMainView;
        }

        /**
         * 控制子view水平滑動的距離,預設是0 不可以滑動
         * @param child
         * @param left
         * @param dx
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }

        /**
         * 功能同上,垂直方向滑動的距離
         * @param child
         * @param top
         * @param dy
         * @return
         */
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return top;
        }

        /**
         * 當拖拽子view之後手指離開螢幕時觸發;
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {

        }
    };

以上程式碼即可實現view滑動的功能。但如果想要實現手指離開螢幕view自動滑動到指定位置的功能時,需要在Callback中重寫onViewReleased()方法。ViewDragHelper提供了smoothSlideViewTo() 方法,可以實現view的自動滑動效果,當然其內部也是通過Scroller類實現的,故需要重寫computeScroll() 方法。

如下是一個模擬google DragLayout的一個Demo,當然只實現了其中側滑的一個小功能,其他事件分發處理邏輯都沒有具體實現。

package com.ts.test.widget;

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;

/**
 * Created by tiansen on 17-11-18.
 */

public class MyDragLayout extends FrameLayout {

    private static final String TAG = "MyDragLayout";
    private ViewDragHelper mViewDragHelper;

    /**
     * 側邊欄View
     */
    private View mMenuView;

    /**
     * 主View
     */
    private View mMainView;

    /**
     * 側邊欄View寬度
     */
    private int mMenuWidth;

    /**
     * 主View寬度
     */
    private int mMainWidth;

    private ViewDragHelper.Callback mCallBack = new ViewDragHelper.Callback() {

        /**
         * 指定可以滑動的子View
         * @param child
         * @param pointerId
         * @return true 指定的子view可以滑動
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mMainView;
        }

        /**
         * 控制子view水平滑動的距離,預設是0 不可以滑動
         * @param child
         * @param left
         * @param dx
         * @return
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            // 控制滑動邊界
            return (left < 0 ? 0 : left) < mMenuWidth ? left : mMenuWidth;
        }

        /**
         * 功能同上,垂直方向滑動的距離
         * @param child
         * @param top
         * @param dy
         * @return
         */
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            return 0;
        }

        /**
         * 當拖拽子view之後手指離開螢幕時觸發;
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            if (mMainView.getLeft() < mMenuWidth / 2) {
                mViewDragHelper.smoothSlideViewTo(mMainView, 0, 0);
                ViewCompat.postInvalidateOnAnimation(MyDragLayout.this);
            } else {
                mViewDragHelper.smoothSlideViewTo(mMainView, mMenuWidth, 0);
                ViewCompat.postInvalidateOnAnimation(MyDragLayout.this);
            }
        }
    };

    public MyDragLayout(Context context) {
        this(context, null);
    }

    public MyDragLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyDragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mViewDragHelper = ViewDragHelper.create(this, mCallBack);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mMenuView = getChildAt(0);
        mMainView = getChildAt(1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mMainWidth = mMainView.getMeasuredWidth();
        mMenuWidth = mMenuView.getMeasuredWidth();
    }


    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        if (mViewDragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
}

相關推薦

Android 實現View滑動方式

關於View的滑動,Android中提供了許多方法,具體可以分為一下幾類: layout 在ACTION_MOVE中通過獲取x、y的偏移量動態佈局view,並禁止向父控制元件傳遞事件: @Override public boolean onTo

Android 實現懸浮的方式(一)AppBarLayout+PtrFrameLayout

先上個圖: 我所知道的有兩種實現方式: AppBarLayout巢狀控制滾動區實現(目前使用的) 給RecyclerView增加HeaderView顯示隱藏切換實現 先把引用的包放出來: compile 'com.android.su

android自定義view方式

convertView = LayoutInflater.from(mContext).inflate(R.layout.list_view_item, null); XXXX = (ItemView)convertView; 假如我想自定義一個listview,我之前的

Android 實現 View 滑動的七方法

記錄下系統提供的 View 滑動的 API 方法。不管採用哪一種方式,本質的思想基本上都是一致的,當觸控 View 的時候,記錄下當前觸控點的座標,當手指移動的時候,記錄移動後的觸控點座標,從而獲取相對上一次座標點的偏移量,通過偏移量來修改 View 的座標,這

Android實現IPC的方式詳細分析及比較

1.使用Bundle   ----> 用於android四大元件間的程序間通訊android的四大元件都可使用Bundle傳遞資料  所以如果要實現四大元件間的程序間通訊 完全可以使用Bundle來實現 簡單方便  2.使用檔案共享  ---->用於單執行緒讀寫

06.實現servlet的方式,以及接口或者類之間的關系

ssa 圖片 servlet 容器 實例化 設備 blog public ide 接口:Servlet、ServletConfig、ServletRequest、ServletResponse、HttpServletRequest、HttpServletResponse、S

JS實現繼承的方式(轉)

多繼承 logs 影響 .cn sta 初始化 定義 附錄 style 轉自:幻天芒的博客 前言 JS作為面向對象的弱類型語言,繼承也是其非常強大的特性之一。那麽如何在JS中實現繼承呢?讓我們拭目以待。 JS繼承的實現方式 既然要實現繼承,那麽首先我們得有一個父類,

JS實現繼承的方式

簡單 成員 類構造 缺陷 屬性 con html 但是 內存 JS實現繼承的幾種方式 前言 JS作為面向對象的弱類型語言,繼承也是其非常強大的特性之一。那麽如何在JS中實現繼承呢?讓我們拭目以待。 JS繼承的實現方式 既然要實現繼承,那麽首先我們得有一個父類,代碼如

JavaScript實現繼承的方式總結一

相同 實踐 extend sta 執行 instance () class new 雖然在ES6中有了繼承,使用extends關鍵字就能實現。本篇講的不是這種,而是ES6之前的幾種實現繼承的方式。 (一)原型鏈 ECMAScript中將原型鏈作為實現繼承的主要方法。其基本思

java實現同步的方式(總結)

副本 增刪改 否則 都是 fin ret 語義 value art 為何要使用同步? java允許多線程並發控制,當多個線程同時操作一個可共享的資源變量時(如數據的增刪改查), 將會導致數據不準確,相互之間產生沖突,因此加入同步鎖以避免在該線程沒有完成操

JS類對象實現繼續的方式

var test 子類實例化 傳參 blog spa sim func prototype 0. ES6可以直接使用class,extends來繼承. 1. 原型繼承 1 2 父類: 3 4 function Persio

JAVASCRIPT實現繼承的方式

JAVASCRIPT實現繼承的幾種方式 對象冒充(多繼承):a. 代碼: function ClassA(sColor) { this.color = sColor; this.sayColor = function () { console.log(this.color); }; } functio

javascript中實現繼承的方式

eat 共享 all cto 原型 構造 child 構造函數 java javascript中實現繼承的幾種方式 1、借用構造函數實現繼承 function Parent1(){ this.name = "parent1" } function Child1()

Android activity間通訊方式

read flag 進程 destroy ads sage on() sting ogl Activity 通訊 Bundle 我們可以通過將數據封裝在Bundle對象中 ,然後在Intent跳轉的時候攜帶Bundle對象 bundle 本質上是使用 arrayMap實現

Android程序間通訊 - 方式的對比總結

什麼是RPC RPC(Remote Procedure Call)即遠端過程呼叫,它是一種通過網路從遠端計算機程式上請求服務,在不需要了解底層網路技術的協議下,即可獲取計算機程序中的資料。RPC使得開發包括網路分散式多程式在內的應用程式更加容易。 RPC在OSI網路通訊7層模型中

javascript 面向物件(實現繼承的方式)

 1、原型鏈繼承 核心: 將父類的例項作為子類的原型 缺點:  父類新增原型方法/原型屬性,子類都能訪問到,父類一變其它的都變了 function Person (name) { this.name =

Android 隱士跳轉方式

1、只有 配置 action 進行跳轉 <intent-filter> <action android:name="testarouter"></action> <category android:name="android.i

WPF實現動畫的方式及其小案例

WPF實現動畫的方式: 基於計時器的動畫         建立一個定時器,然後根據其頻率迴圈呼叫函式或者一個事件處理函式,在這個函式中可以手工更新目標屬性,直到達到最終值,這時可以停止計時器。 案例: 效果圖:

實現同步的方式

1.同步方法即有synchronized關鍵字修飾的方法;由於Java的每個物件都有一個內建鎖,當用此關鍵字修飾方法時,內建鎖會保護整個方法。在呼叫該方法之前,需要獲取內建鎖,否則就處於阻塞狀態。2.同步程式碼塊即有synchronized關鍵字修飾的語句塊;程式碼如:synchronized(object)

Android實現延遲的方法小結

本文例項總結了Android實現延遲的幾種方法。分享給大家供大家參考,具體如下: 一、通過Thread new Thread(){ public void run(){ sleep(***); } }.start(); 通過ProgressDialog的使用來