您的位置:首页 > 其它

用ViewDraghelper实现侧滑面板

2015-09-22 15:12 555 查看
首先自定义一个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。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: