用ViewDraghelper實現側滑面板

首先自定義一個DragLayout繼承FrameLayout,重寫三個構造方法,並用this進行層級調用。

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

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

	public DragLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
然後分三個步驟:實現DragLayout的子view的拖拽

1. 創建ViewDragHelper輔助類

public DragLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		
		// 1.創建ViewDragHelper輔助類
		mHelper = ViewDragHelper.create(this, 1.0f, callback);
	}
2.轉交觸摸事件

// 2.轉交觸摸事件
	public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
		return mHelper.shouldInterceptTouchEvent(ev);
	};
	public boolean onTouchEvent(android.view.MotionEvent event) {
		try {
			mHelper.processTouchEvent(event);
		} catch (Exception e) {
			
		}
		return true;
	};
3.複寫回調callback

// 3.複寫回調方法
	Callback callback = new Callback() {
		
		// a.返回true 表示所有面板均可拖拽  返回false  表示所有面板均不可拖拽
		@Override
		public boolean tryCaptureView(View child, int pointerId) {
			return true;
		}
}
再重寫callback的另一個方法,clampViewPositionHorizontal,即可實現子view的拖拽。

// 返回值表示水平方向的拖拽位移
		@Override
		public int clampViewPositionHorizontal(View child, int left, int dx) {
			
			left = fixLeft(left);
			return left;
		}
下面是callback中可能用到的另外幾個方法的介紹:

1.getViewHorizontalDragRange

此方法用於限制子view的橫向拖拽範圍。在複寫其之前,可以先複寫DragLayout的onSizeChanged方法,獲取屏幕的寬和高,然後根據高度值求出mRange。mRange就是子view的橫向拖拽範圍。

// 獲得容器的寬高,計算主面板的最大拖拽範圍
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		mHeight = getMeasuredHeight();
		mWidth = getMeasuredWidth();
		
		mRange = (int)(mWidth * 0.6f);
	}

// 限制主面板的拖拽範圍
		@Override
		public int getViewHorizontalDragRange(View child) {
			return mRange;
		}
2.onViewPositionChanged

此方法適用於處理當子view位置發生改變時要做的操作,如:將側滑面板的位移值轉交給主面板,側滑面板開關時的伴隨動畫,狀態的更新以及監聽回調。

這裏我將上面所列項目都實現了,下面是附上的代碼,最後會附上完整代碼。

在此之前,複寫DragLayout的onFinishInflate方法,獲得所有子view的引用。

// 獲得容器中的子view
	protected void onFinishInflate() {
		mLeft = (LinearLayout) getChildAt(0);
		mMain = (LinearLayout) getChildAt(1);
	};

位移值轉交

// 將左面板的位移轉交給主面板
			if(changedView == mLeft)
			{
				mLeft.layout(0, 0, mWidth, mHeight);
				int newLeft = mMain.getLeft() + dx;
				newLeft = fixLeft(newLeft);
				mMain.layout(newLeft,0,newLeft+mWidth,mHeight);
			}

private int fixLeft(int left) {
			if(left < 0)
			{
				left = 0;
			}else if(left > mRange)
			{
				left = mRange;
			}
			return left;
		}
伴隨動畫

float percent = mMain.getLeft() * 1.0f / mRange;
		
		// 1. 左面板:縮放動畫,平移動畫,透明度變化
		ViewHelper.setScaleX(mLeft, evaluate(percent, 0.5f, 1.0f));
		ViewHelper.setScaleY(mLeft, evaluate(percent, 0.5f, 1.0f));
		ViewHelper.setTranslationX(mLeft, evaluate(percent, -mWidth/2, 0));
		ViewHelper.setAlpha(mLeft, evaluate(percent, 0.5f, 1.0f));
		// 2. 主面板:縮放動畫
		ViewHelper.setScaleX(mMain, evaluate(percent, 1.0f, 0.8f));
		ViewHelper.setScaleY(mMain, evaluate(percent, 1.0f, 0.8f));
狀態更新和監聽回調

public interface OnDragUpdateListener{
		void onOpen();
		void onClose();
		void onDragging(float percent);
	}
	
	private OnDragUpdateListener onDragUpdateListener;
	
	public static enum Status{
		Open,Close,Dragging;
	}
	
	private Status status = Status.Close;
	public Status getStatus() {
		return status;
	}

	public void setStatus(Status status) {
		this.status = status;
	}

	public OnDragUpdateListener getOnDragUpdateListener() {
		return onDragUpdateListener;
	}

	public void setOnDragUpdateListener(OnDragUpdateListener onDragUpdateListener) {
		this.onDragUpdateListener = onDragUpdateListener;
	}
if(onDragUpdateListener != null)
		{
			onDragUpdateListener.onDragging(percent);
		}
		
		Status lastStatus = status;
		if(percent == 0)
		{
			status = Status.Close;
		}else if(percent == 1)
		{
			status = Status.Open;
		}else
		{
			status = Status.Dragging;
		}
		
		if(status != lastStatus)
		{
			if(status == Status.Close)
			{
				onDragUpdateListener.onClose();
			}else if(status == Status.Open)
			{
				onDragUpdateListener.onOpen();
			}
		}
3.onViewReleased

此方法用於處理子view釋放時要做的操作:如結束動畫

// 當子view釋放時要做的事,如:結束動畫
		@Override
		public void onViewReleased(View releasedChild, float xvel, float yvel) {
			if(xvel == 0 && mMain.getLeft() > mRange * 0.5f)
			{
				open();
			}else if(xvel > 0)
			{
				open();
			}else
			{
				close();
			}
		}
// 關閉側滑面板的操作
	protected void close() {
		close(true);
	}

	public void close(boolean isSmooth)
	{
		int finalLeft = 0;
		if(isSmooth)
		{
			// 1.觸發平滑動畫
			if(mHelper.smoothSlideViewTo(mMain, finalLeft, 0))
			{
				ViewCompat.postInvalidateOnAnimation(this);
			}
		}else
		{
			mMain.layout(finalLeft, 0, finalLeft+mWidth, mHeight);
		}
	}
	// 打開側滑面板的操作
	protected void open() {
		open(true);
	}
	
	public void open(boolean isSmooth)
	{
		int finalLeft = mRange;
		if(isSmooth)
		{
			// 1.觸發平滑動畫
			if(mHelper.smoothSlideViewTo(mMain, finalLeft, 0))
			{
				ViewCompat.postInvalidateOnAnimation(this);
			}
		}else
		{
			mMain.layout(finalLeft, 0, finalLeft+mWidth, mHeight);
		}
	}
	
	// 2.維持平滑動畫
	@Override
	public void computeScroll() {
		if(mHelper.continueSettling(true))
		{
			ViewCompat.postInvalidateOnAnimation(this);
		}
	}
下面是使用DragLayout,首先是activity_main.xml文件

<com.demo.viewdraghelperdemo.DragLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/dl"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg" >

    <LinearLayout
        android:id="@+id/ll_left"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:paddingBottom="50dp"
        android:paddingLeft="10dp"
        android:paddingRight="50dp"
        android:paddingTop="50dp" >

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_vertical"
            android:src="@drawable/header" />

        <ListView
            android:id="@+id/lv_left"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    </LinearLayout>

    <com.demo.viewdraghelperdemo.MyLinearLayout
        android:id="@+id/ll_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ffffff"
        android:orientation="vertical" >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:background="#9DD4FB" >

            <ImageView
                android:id="@+id/iv_header"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dp"
                android:src="@drawable/header" />
        </RelativeLayout>

        <ListView
            android:id="@+id/lv_main"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" >
        </ListView>
    </com.demo.viewdraghelperdemo.MyLinearLayout>

</com.demo.viewdraghelperdemo.DragLayout>
MainActivity.java

package com.demo.viewdraghelperdemo;

import java.util.Random;

import android.animation.ObjectAnimator;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.CycleInterpolator;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.demo.viewdraghelperdemo.DragLayout.OnDragUpdateListener;
import com.nineoldandroids.view.ViewHelper;

public class MainActivity extends Activity {

	private ImageView header;
	private DragLayout dl;
	private MyLinearLayout ll_main;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		final ListView lv_left = (ListView) findViewById(R.id.lv_left);
		lv_left.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Strings.list1){
			@Override
			public View getView(int position, View convertView, ViewGroup parent) {
				TextView v =  (TextView) super.getView(position, convertView, parent);
				v.setTextColor(Color.WHITE);
				return v;
			}
		});
		
		ListView lv_main = (ListView) findViewById(R.id.lv_main);
		lv_main.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, Strings.list2){
			@Override
			public View getView(int position, View convertView, ViewGroup parent) {
				TextView v = (TextView) super.getView(position, convertView, parent);
				v.setTextColor(Color.BLACK);
				return v;
			}
		});
		
		dl = (DragLayout) findViewById(R.id.dl);
		
		header = (ImageView) findViewById(R.id.iv_header);
		header.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				dl.open();
			}
		});
		
		ll_main = (MyLinearLayout) findViewById(R.id.ll_main);
		ll_main.setDragLayout(dl);
		dl.setOnDragUpdateListener(new OnDragUpdateListener() {
			
			@Override
			public void onOpen() {
				Random r = new Random();
				lv_left.smoothScrollToPosition(r.nextInt(20));
			}
			
			@Override
			public void onDragging(float percent) {
				ViewHelper.setAlpha(header, (1 - percent) * 0.5f + 0.5f);
			}
			
			@Override
			public void onClose() {
				ObjectAnimator animator = ObjectAnimator.ofFloat(header, "translationX", 15);
				animator.setInterpolator(new CycleInterpolator(5));
				animator.setDuration(500);
				animator.start();
			}
		});
	}
}
String.java,用於填充兩個ListView的含有兩個靜態字符串數組的類

package com.demo.viewdraghelperdemo;

public class Strings {

	public static String[] list1 = { "dugubaitian", "xuanxuan", "yueer",
			"chennan", "yuxin", "longwu", "dongfangfenghuang", "chuyu",
			"tantaixuan", "mengkeer", "xiaochen", "qingqing", "yefan",
			"jiziyue", "qinlan", "anmiaoyi", "shihao", "huolinger",
			"taiyinyutu" };

	public static String[] list2 = { "shenmu", "busibumie", "changshengjie",
			"zhetian", "wanmeishijie", "gaoshoujimo", "xinyueyongheng", "wang",
			"qingyuxie", "zanmingming", "duxingaoshouzaidushi", "jixiemori",
			"chongfengxing", "youmingxiantu", "xijue", "dongni", "lanbenjiayi",
			"dadizhideng", "jipinmeinvdiguo", "xiaoyaofangdong",
			"wanmeirensheng","taoyunqingnian"};
}
最後,爲了屏蔽當側滑面板打開時,主面板的滑動事件,自定義了一個LinearLayout,MyLinearLayout.java

package com.demo.viewdraghelperdemo;

import com.demo.viewdraghelperdemo.DragLayout.Status;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.LinearLayout;

public class MyLinearLayout extends LinearLayout {

	private DragLayout layout;
	public void setDragLayout(DragLayout layout)
	{
		this.layout = layout;
	}
	
	public MyLinearLayout(Context context) {
		super(context);
	}

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

	public MyLinearLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}
	
	
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		if(layout.getStatus() == Status.Close)
			return super.onInterceptTouchEvent(ev);
		else
		{
			return true;
		}
	}
	
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if(layout.getStatus() == Status.Close)
			return super.onTouchEvent(event);
		else
		{
			try {
				
				layout.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			return true;
		}
	}

}
要運行這個工程可能要用到兩個jar包,sdk\extras\android\support\v4\android-support-v4.jar和nineoldandroids.jar。















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章