Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 安卓開發之ViewDragHelper的使用及自定義可下拉展示內容的ViewGroup

安卓開發之ViewDragHelper的使用及自定義可下拉展示內容的ViewGroup

編輯:關於Android編程

一、ViewDragHelper

一個自定義ViewGroup的工具類,它提供了許多有用的方法和狀態允許用戶去拖拽和繪制子View在自定義ViewGroup中的軌跡和位置。

ViewDragHelper的創建;

ViewDragHelper可以使用靜態方法創建一個實例:

ViewDragHelper.create(ViewGroup forParent,int sensitiveity,ViewDragHelper.Callback cb)

在自定義ViewGroup中,ViewDragHelper可以幫助我們來分析手勢和處理拖動。

@Override
public boolean onTouchEvent(MotionEvent event) {
        try {
        //處理觸摸事件
        mDragHelper.processTouchEvent(event);
        } catch (Exception e) {
        e.printStackTrace();
        }
        //返回true,
        return true;
}

使用ViewDragHelper來動態移動自定義ViewGroup中的控件:

public boolean smoothSlideViewTo(View child, int finalLeft, int finalTop)

// Animate the view child to the given (left, top) position.
// 返回true 代表還沒有移動到指定的位置,需要刷新界面,繼續移動
// 返回false 就停止工作

二、 ViewDragHelper.Callback

ViewDragHelper.Callback集成了許多可覆寫的方法,所有移動的控制在ViewDragHelper.Callback裡面來實現。

是否可以捕捉ViewGroup中的子組件:

public boolean tryCaptureView(View child, int pointerId) {

//返回true,就代表著可對該子組件處理滑動事件。否則就不會處理。 

return true;
//只對特定的組件捕捉 return speChild == child;

}

clampViewPositionHorizontal[Vertical]:

處理子組件在水平或者豎直方向的滑動限制,在這個方法內部做子組件的邊界處理,就是確保子組件不會滑過界。

例如在豎直方向進行滑動時,一般先獲取控件可滑動到的頂端Y值底端Y值,再進行一個取值

@Override
public int clampViewPositionVertical(View child, int top, int dy) {

//手指觸摸移動時實時回調, top表示要到的y位置

    int topBound = ...;
    int bottomBound = ...;
    return Math.min(Math.max(topBound, top), bottomBound);

}

onViewPositionChanged
當前拖動的子組件位置變化時調用的方法。一般在該方法裡調整其他子組件的位置。

@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {

    //changedView為當前位置發生改變的View,left,top分別為該View的left和top坐標

} 

onViewReleased

當手指釋放的時候會調用的方法。在這個方法裡實現松開時的滑動效果。

@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {

    //released 為釋放的View,xvel,yvel分別為該手指離開時滑動和豎直滑動的速度

} 

getViewVertical[Horizontal]DragRangeHorizontal

 @Override
    public int getViewVerticalDragRange(View child) {
       //返回當前捕捉的child子組件的豎直滑動范圍
        return ...;
    }

……

三、ViewDragHelper的使用

自定義可下拉展示內容的的ViewGroup

效果圖:

這裡寫圖片描述<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMyBpZD0="一自定義viewgroupdragdownlayout">一、自定義ViewGroup:DragDownLayout

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

/**
 * Created by cxm on 2016/8/22.
 */
public class DragDownLayout extends ViewGroup {

    private ViewDragHelper dragHelper;

    //下拉的控件和內容控件
    private View mDragbar, mContentView;
    private int dragRange;

    //對外的接口
    private OnOpenListener mOnOpenListener;
    private OnCloseListener mOnCloseListener;

    private boolean isOpen;//內容是否打開著

    public DragDownLayout(Context context) {
        super(context);
        init();
    }

    public DragDownLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public DragDownLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public DragDownLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init() {
        dragHelper = ViewDragHelper.create(this, mCallback);
    }

    @Override
    protected void onLayout(boolean b, int l, int t, int r, int bo) {
        mDragbar.layout(0, 0, getWidth(), mDragbar.getMeasuredHeight());
        mContentView.layout(0, -mContentView.getMeasuredHeight(), getWidth(), 0);
    }

    @Override
    public boolean onInterceptHoverEvent(MotionEvent event) {
        final int action = MotionEventCompat.getActionMasked(event);
        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
            dragHelper.cancel();
            return false;
        }
        return dragHelper.shouldInterceptTouchEvent(event);
    }

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

    private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mDragbar;
        }

        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            mContentView.layout(0, top-mContentView.getHeight(), getWidth(), top );
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            int topBound = getPaddingTop();
            int bottomBound = getHeight() - mDragbar.getHeight();
            return Math.min(Math.max(topBound, top), bottomBound);
        }

        @Override
        public int getViewVerticalDragRange(View child) {
            dragRange = mContentView.getHeight();
            return dragRange;
        }


        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {

            //下拉的位置大於內容控件的1/2時,則向下滑動到底

            if (mContentView.getBottom()>mContentView.getHeight()/2) {
                smoothToBottom();
            } else if (mContentView.getBottom()<=mContentView.getHeight()/2) {
                smoothToTop();
            }
            invalidate();
        }


    };


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        mDragbar = getChildAt(0);
        mContentView = getChildAt(1);

        LayoutParams contPar = mDragbar.getLayoutParams();
        //父容器給內容組件指定大小
        int heighContentSpec = MeasureSpec.makeMeasureSpec(contPar.height, MeasureSpec.EXACTLY);
        //測量子組件,內容組件寬隨父布局
        mDragbar.measure(widthMeasureSpec, heighContentSpec);

        LayoutParams delPar = mContentView.getLayoutParams();

        int heightDelSpec = MeasureSpec.makeMeasureSpec(delPar.height, MeasureSpec.EXACTLY);

        mContentView.measure(widthMeasureSpec, heightDelSpec);

        //父布局設置最終的寬和高,寬沿用自己測量自己的widthMeasureSpec,高度使用內容布局的高度
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), contPar.height+delPar.height);
    }


    private void smoothToTop() {
        if (dragHelper.smoothSlideViewTo(mDragbar, getPaddingLeft(), getPaddingTop())) {
            ViewCompat.postInvalidateOnAnimation(this);
            isOpen = false;
            if(mOnCloseListener!=null) mOnCloseListener.close();
        }
    }

    private void smoothToBottom() {
        if (dragHelper.smoothSlideViewTo(mDragbar, getPaddingLeft(), getHeight()-getPaddingBottom()-mDragbar.getHeight())) {
            ViewCompat.postInvalidateOnAnimation(this);
            isOpen = true;
            if(mOnOpenListener!=null) mOnOpenListener.open();
        }
    }

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

    public boolean isOpen(){
        return isOpen;
    }

    public void openContent(){
        if(!isOpen) smoothToBottom();
    }

    public void closeContent(){
        if(isOpen) smoothToTop();
    }

    public interface OnOpenListener{
        void open();
    }

    public interface OnCloseListener{
        void close();
    }



    public void setOnOpenListener(OnOpenListener mOnOpenListener) {
        this.mOnOpenListener = mOnOpenListener;
    }

    public void setOnCloseListener(OnCloseListener mOnCloseListener) {
        this.mOnCloseListener = mOnCloseListener;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() != 2) {
            throw new IllegalStateException("Just contain two Views/ViewGroups ");
        }
    }
}

二、在xml布局文件中使用DragDownLayout

使用時要標明拖拽控件和內容控件的高度。



    

    


三、對DragDownLayout設置監聽

mDragDownLayout = (DragDownLayout) findViewById(R.id.myDragDownLayout);

mDragDownLayout.setOnOpenListener(new DragDownLayout.OnOpenListener() {
        @Override
        public void open() {
            Toast.makeText(MainActivity.this,"open",Toast.LENGTH_SHORT).show();
        }
    });

Github:

DragDownLayout

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved