-
xml
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<com.guyulei.myqq50.DragLayout
android:background="@mipmap/bk"
android:id="@+id/dl_dragLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:background="#f00"
android:layout_width="200dp"
android:layout_height="match_parent">
<RelativeLayout
android:background="#0ff"
android:layout_width="match_parent"
android:layout_height="150dp">
<ImageView
android:layout_marginLeft="15dp"
android:layout_centerVertical="true"
android:src="@mipmap/qq4"
android:layout_width="135dp"
android:layout_height="135dp"/>
</RelativeLayout>
<ListView
android:id="@+id/left_listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:background="#0f0"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:background="#f0f"
android:layout_width="match_parent"
android:layout_height="88dp">
<ImageView
android:id="@+id/iv_head"
android:layout_marginLeft="15dp"
android:layout_centerVertical="true"
android:src="@mipmap/qq4"
android:layout_width="77dp"
android:layout_height="77dp"/>
</RelativeLayout>
<ListView
android:id="@+id/main_listView"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
</com.guyulei.myqq50.DragLayout>
</LinearLayout>
2.自定義view
public class DragLayout extends FrameLayout
package com.guyulei.myqq50;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
/**
* Created by Administrator on 2016/6/30 0030.
* 1、為什麼不繼承 ViewGroup,因為繼承 ViewGroup 需要重寫 onMeasure()和實作 onLayout()方法,自己
* 實作子 view 的測量和擺放,在這裡我們不需要自己去做測量和擺放,而 FrameLayout 已經對這兩個方法進
* 行了具體實作,是以繼承 FrameLayout 更加簡單省事
* 2、為什麼不繼承 RelativeLayout,因為這裡我們隻需要層級關系,不需要相對關系,繼承 RelativeLayout
* 界面效果是一樣的,但 RelativeLayout 對 FrameLayout 多了相對關系的計算,效率會低一些,是以選擇繼
* 承 FrameLayout
*/
public class DragLayout extends FrameLayout {
private ViewDragHelper mViewDragHelper;
private LinearLayout mLeftContent;
private LinearLayout mMainContent;
private int mWidth;
private int mHeight;
private int mRange;
private int mLeftWidth;
//狀态值
public enum Status {
Open,
Close,
Draging;
}
//預設狀态值
private Status status = Status.Close;
//監聽對象聲明
private OnUpdataDragStateListener mOnUpdataDragStateListener;
//對外接口
public interface OnUpdataDragStateListener {
void onOpen();
void onClose();
void onDragging(float percent);
}
//對外接口回調方法
public void setOnUpdataDragStateListener(OnUpdataDragStateListener onUpdataDragStateListener) {
this.mOnUpdataDragStateListener = onUpdataDragStateListener;
}
//串聯構造方法
/**
* 我們可以通過串連三個構造方法的方式實作隻調用一次 init()方法
* 這樣無論是代碼建立還是布局在 xml 中都能調用到我們的初始化代碼
*
* @param context
*/
//代碼建立時調用
public DragLayout(Context context) {
this(context, null);
}
//布局在 xml 中,執行個體化時調用
public DragLayout(Context context, AttributeSet attrs) {
this(context, attrs, );
}
public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//初始化
//1.輔助類ViewDragHelper forparent 2個拖拽控件的父控件 ,sensitivity子控件拖拽的敏感度
//callback:事件回調
mViewDragHelper = ViewDragHelper.create(this, f, new ViewDragHelper.Callback() {
@Override
// tryCaptureView俘獲; 奪取; 奪得(嘗試奪取子控件)
//傳回值代表 子控件 是否可以被奪取
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
//可通過計算測量水準或者垂直方向拖拽的範圍 傳回>0即可
@Override
public int getViewHorizontalDragRange(View child) {
return mRange;
}
@Override
//clamp緊緊抓住; 緊夾住(緊抓着俘獲的view(child)水準或者垂直移動位置)
//dx 變化量(移動的內插補點 newleft-oldleft)
public int clampViewPositionHorizontal(View child, int left, int dx) {
//dx累加 是 left
if (child == mMainContent) {
//拖拽為主面闆時
left = fixleft(left);
}
return left;
}
@Override
//松手時 回調(Released釋放)
public void onViewReleased(View releasedChild, float xvel, float yvel) {
// xvel水準方向上的速度 左為- 右為+
if (xvel == && mMainContent.getLeft() > mRange / ) {
open();
} else if (xvel > ) {
//有向右的速度
open();
} else {
close();
}
}
//位置發生移動 調用
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == mLeftContent) {
//控制底下的子控件不能移動(左面闆)
mLeftWidth = mLeftContent.getMeasuredWidth();
mLeftContent.layout(, , mLeftWidth, mHeight);
//左面闆移動的距離 累加給主面闆(移動左面闆)
int oldLeft = mMainContent.getLeft();
int newLeft = oldLeft + dx;
//修正左邊的位置
newLeft = fixleft(newLeft);
mMainContent.layout(newLeft, , newLeft + mWidth, mHeight);
}
// dispatch派遣,排程; (迅速地)發出; 迅速處理
dispatchEvent();
invalidate();
}
});
}
//2 mViewDragHelper搶過觸摸事件自己決定應該怎麼處理
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
//3.mViewDragHelper搶過觸摸事件後,進行處理,傳回值true
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
}
//4.onFinishInflate()在控件 inflate 完成時會被調用查找子控件
//可以通過 findViewById()的方式查找子控件 getChildAt(0)
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mLeftContent = (LinearLayout) getChildAt();
mMainContent = (LinearLayout) getChildAt();
}
// 5.onSizeChanged()調用的次數比 onMeasure()少,在這裡我們在 onSizeChanged()方法中去擷取寬高
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//擷取整個控件的寬度和高度
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
//主界面拖拽的範圍(自定義)(0-mRange)(0 < left <mRange)
mRange = (int) (mWidth * f);
}
//6.修正左邊的距離
private int fixleft(int left) {
if (left < ) {
left = ;
} else if (left > mRange) {
left = mRange;
}
return left;
}
//7.打開 smooth變平和,變緩和;Slide Mountain 斯來得山(凱次克來最高峰)
//View child, int finalLeft, int finalTop
private void open() {
open(true);
}
private void open(boolean isSmooth) {
int finalLeft = mRange;
if (isSmooth) {
//開啟平滑
if (mViewDragHelper.smoothSlideViewTo(mMainContent, finalLeft, )) {
//重繪界面 Compat相容性; postInvalidateOnAnimation 動畫結束之後再重繪 防止丢幀
ViewCompat.postInvalidateOnAnimation(this);
} else {
mMainContent.layout(finalLeft, , finalLeft + mWidth, mHeight);
}
}
}
//8. 關閉
private void close() {
close(true);
}
private void close(boolean isSmooth) {
int finalLeft = ;
if (isSmooth) {
//開啟平滑
if (mViewDragHelper.smoothSlideViewTo(mMainContent, finalLeft, )) {
//重繪界面
//invalidate();
ViewCompat.postInvalidateOnAnimation(this);
} else {
mMainContent.layout(finalLeft, , finalLeft + mWidth, mHeight);
}
}
}
@Override
public void computeScroll() {
super.computeScroll();
//維持動畫
if (mViewDragHelper.continueSettling(true)) {
//重繪
ViewCompat.postInvalidateOnAnimation(this);
}
}
//9.加動畫 回調
private void dispatchEvent() {
//擷取 百分百 0.0f - 1.0f
float percent = mMainContent.getLeft() * f / mRange;
Status lastStatus = status;
//狀态更新
if (percent == ) {
status = Status.Close;
} else if (percent == ) {
status = Status.Open;
} else {
status = Status.Draging;
}
//接口回調
if (mOnUpdataDragStateListener != null) {
mOnUpdataDragStateListener.onDragging(percent);
}
//
if (lastStatus != status && mOnUpdataDragStateListener != null) {
if (status == Status.Open) {
mOnUpdataDragStateListener.onOpen();
} else if (status == Status.Close) {
mOnUpdataDragStateListener.onClose();
}
}
//左面闆 縮放 位移 透明的
//0.0f-1.0f ---0.5f-1.0f
//0.5f + percent * (0.5f);
mLeftContent.setScaleX(f + percent * (f));
mLeftContent.setScaleY(f + percent * (f));
//位移 evaluate(percent,-mw,0)
mLeftContent.setTranslationX(evaluate(percent, -mWidth * f, f));
//透明的evaluate(percent,0.2f,1.0f)
mLeftContent.setAlpha(evaluate(percent, f, f));
//主面闆 縮放evaluate(percent,0.2f,1.0f)
mMainContent.setScaleY(evaluate(percent, f, f));
//背景亮度 濾波器Filter 估價,估值evaluate 門童; 搬運勞工Porter欺騙; 把…改頭換面;Duff
getBackground().setColorFilter((Integer) evaluateColor(percent, Color.BLACK, Color.TRANSPARENT), PorterDuff.Mode.SRC_OVER);
}
public Object evaluateColor(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> ) & ;
int startR = (startInt >> ) & ;
int startG = (startInt >> ) & ;
int startB = startInt & ;
int endInt = (Integer) endValue;
int endA = (endInt >> ) & ;
int endR = (endInt >> ) & ;
int endG = (endInt >> ) & ;
int endB = endInt & ;
return (int) ((startA + (int) (fraction * (endA - startA))) << ) |
(int) ((startR + (int) (fraction * (endR - startR))) << ) |
(int) ((startG + (int) (fraction * (endG - startG))) << ) |
(int) ((startB + (int) (fraction * (endB - startB))));
}
public Float evaluate(float fraction, Number startValue, Number endValue) {
float startFloat = startValue.floatValue();
return startFloat + fraction * (endValue.floatValue() - startFloat);
}
}
3.MainActivity
public class MainActivity extends Activity
package com.guyulei.myqq50;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
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 java.util.Random;
import utils.MyToast;
public class MainActivity extends Activity {
private DragLayout mDragLayout;
private ListView mMainlistView;
private ListView mLeftlistView;
private ImageView mIvhead;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//首頁面imag對象
mIvhead = (ImageView) findViewById(R.id.iv_head);
mDragLayout = (DragLayout) findViewById(R.id.dl_dragLayout);
mDragLayout.setOnUpdataDragStateListener(new DragLayout.OnUpdataDragStateListener() {
@Override
public void onOpen() {
MyToast.showToast(getApplicationContext(), "onOpen");
面闆打開時,左面闆上的 listview 随機滑動到 0 到 50 間的某個位置
mLeftlistView.smoothScrollToPosition(new Random().nextInt());
}
@Override
public void onClose() {
MyToast.showToast(getApplicationContext(), "onClose");
ValueAnimator valueAnimator = ValueAnimator.ofFloat(f, f);
valueAnimator.setDuration();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
mIvhead.setTranslationX(value);
}
});
//動畫插值器
valueAnimator.setInterpolator(new CycleInterpolator());
valueAnimator.start();
}
@Override
public void onDragging(float percent) {
MyToast.showToast(getApplicationContext(), "onDragging" + percent);
//percent 0.0f -> 1.0f => 1.0f -> 0.0f ==> 1-percent
mIvhead.setAlpha(-percent);
}
});
//
mMainlistView = (ListView) findViewById(R.id.main_listView);
//main資料
String[] str_main = new String[]{"guyulei", "guyulei1", "guyulei2", "guyulei3", "guyulei4"
, "guyulei5", "guyulei6", "guyulei7", "guyulei8", "guyulei9", "guyulei10",
"guyulei", "guyulei1", "guyulei2", "guyulei3", "guyulei4"
, "guyulei5", "guyulei6", "guyulei7", "guyulei8", "guyulei9", "guyulei10",
"guyulei", "guyulei1", "guyulei2", "guyulei3", "guyulei4"
, "guyulei5", "guyulei6", "guyulei7", "guyulei8", "guyulei9", "guyulei10"};
//設定擴充卡:ArrayAdapter
mMainlistView.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, str_main) {
@Override
//重新getView 改變字型顔色
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView) super.getView(position, convertView, parent);
view.setTextColor(Color.BLUE);
return view;
}
});
//
mLeftlistView = (ListView) findViewById(R.id.left_listView);
String[] str_left = new String[]{"顧雨磊", "顧雨磊1", "顧雨磊2", "顧雨磊3", "顧雨磊4"
, "顧雨磊5", "顧雨磊6", "顧雨磊7", "顧雨磊8", "顧雨磊9", "顧雨磊10", "顧雨磊11"
, "顧雨磊12", "顧雨磊13", "顧雨磊14", "顧雨磊15", "顧雨磊16", "顧雨磊17", "顧雨磊18"
, "顧雨磊19"};
mLeftlistView.setAdapter(new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_list_item_1, str_left) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView view = (TextView) super.getView(position, convertView, parent);
view.setTextColor(Color.BLACK);
return view;
}
});
}
}