用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。















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值