首先自定義一個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。