/**
* Created by Administrator on 2016/x/xx.
* 創建自定義控件
*/
public class Draglayout extends FrameLayout {
private ViewDragHelper helper;
...
public Draglayout(Context context, AttributeSet attrs, int defStyleAttr) {
...
}
/**
* 初始化控件
* Google I/O ViewDragHelper封裝了觸摸,滑動等操作,可以輕鬆的控件觸摸滑動
*/
private void init() {
//創建ViewDragHelper
//參數1 : 爲誰處理觸摸操作
helper = ViewDragHelper.create(this,callback);
}
/**
* 新建一個callback
*/
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
/**
* 嘗試捕獲視圖
* @param child 被捕獲的子視圖
* @param pointerId 多指觸摸,某個手指的id
* @return 如果返回true,表示所有的孩子都可以被觸摸,返回true表示可以移動
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
return true;
}
/**
* 處理水平移動
* @param child 被觸摸的孩子
* @param left oldLeft + dx = newLeft
* @param dx 系統每隔一段時間檢測手指移動的距離
* @return
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
/**
* 處理垂直移動
* @param child
* @param top
* @param dy
* @return
*/
// @Override
// public int clampViewPositionVertical(View child, int top, int dy) {
// return top;
// }
};
/**
* 讓helper接手觸摸事件的處理
* @param event
* @return 必須返回true才能處理
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
helper.processTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return helper.shouldInterceptTouchEvent(ev);
}
}
- 處理滑動的最大範圍:DrawLayout -- 1.在當前控件及其子控件全部測量完的時候,調用此方法。
/*自定義控件的4個基本流程
* 1,加載
* 2,測量
* 3,佈局
* 4,繪製
* */
/**
* 在當前控件及其子控件全部加載完畢時,調用此方法
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//對當前加入的控件的子視圖進行限制
//代碼健壯性處理
//孩子的數目不能超過2個
if(getChildCount() != 2) {
throw new RuntimeException("Are you kedding me?there only hava two childs");
}
//必須包含ViewGroup
if(!(getChildAt(0) instanceof ViewGroup) || !(getChildAt(1) instanceof ViewGroup)) {
throw new RuntimeException("hehe,you never can use it if it isn't ViewGroup");
}
menu = getChildAt(0);
main = getChildAt(1);
}
- 處理滑動的最大範圍:DrawLayout -- 2.獲取在onMeasure方法執行後執行,可以獲得測量結果
/**
* 在onMeasure()方法執行後執行,可以獲得測量結果
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
int width = main.getMeasuredWidth();
//獲取最大拖動範圍
maxDragRange = (int) (width * 0.6f);
}
- 處理滑動的最大範圍:DrawLayout -- 處理移動的最大範圍
/**
* 新建一個callback
*/
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
...
...
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//處理滑動的最大範圍
if(child == main) {
if(left < 0) {
left = 0;
} else if(left > maxDragRange) {
left = maxDragRange;
}
}
return left;
}
...
};
/**
* Created by Administrator on 2016/9/30.
* 創建自定義控件
*/
public class Draglayout extends FrameLayout {
private ViewDragHelper helper;
private View menu;
private View main;
private int maxDragRange;
...
...
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
...
/**
* 位置已經便改變的回掉方法
* @param changedView 被改變位置的孩子視圖
* @param left 已經移動的left
* @param top
* @param dx 手指移動的dx
* @param dy
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
//判斷當前的視圖是menu的時候
//1.禁止menu滑動
//2.將meun移動的距離傳給main
if(changedView == menu) {
//滑動的底層都是調用這個代碼
menu.offsetLeftAndRight(-dx);
//處理滑動menu造成menu移動的邊界範圍
int oldLeft = main.getLeft();
int newLeft = oldLeft + dx;
//限制newLeft的範圍
if(newLeft > maxDragRange) {
newLeft = maxDragRange;
} else if(newLeft < 0) {
newLeft = 0;
}
int newDx = newLeft - oldLeft;
main.offsetLeftAndRight(newDx);
}
}
...
};
...
}
public class Draglayout extends FrameLayout {
...
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
...
/**
* 釋放視圖的回調
* @param releasedChild 被釋放的孩子視圖
* @param xvel 釋放瞬間x方向的速度
* @param yvel
*/
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
super.onViewReleased(releasedChild, xvel, yvel);
//判斷當釋放視圖的時候,main的左邊距與最大範圍的一半進行比較
if(main.getLeft() < maxDragRange / 2) {
close();
} else {
open();
}
}
...
};
/**
* 開啓側滑菜單
*/
private void open() {
//設置目標點
//平滑的開始滾動視圖
if(helper.smoothSlideViewTo(main,maxDragRange,0)) {
//繪製界面
invalidate();
}
}
/**
* 計算滾動過程中的某幀
*/
@Override
public void computeScroll() {
super.computeScroll();
if(helper.continueSettling(true)) {
invalidate();
}
}
/**'
* 關閉側滑菜單
*/
private void close() {
if(helper.smoothSlideViewTo(main,0,0)) {
//繪製界面
invalidate();
}
}
...
}
...
public class Draglayout extends FrameLayout {
...
/**
* 新建一個callback
*/
private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
...
/**
* 位置已經便改變的會掉方法
* @param changedView 被改變位置的孩子視圖
* @param left 已經移動的left
* @param top
* @param dx 手指移動的dx
* @param dy
*/
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
...
if(changedView == menu) {
...
}
//計算移動的距離佔總距離的百分比
float percent = main.getLeft() * 1.0f / maxDragRange;
executeAnimation(percent);
}
...
};
/**
* 執行移動時main的縮放動畫
* @param percent
*/
private void executeAnimation(float percent) {
// Log.i("test", "executeAnimation: percent=" + percent);
//1.讓main越來越小 : 1.0f - 0.75f
//估值器.插值器
float evaluateResult = evaluate(percent,1.0f,0.75f);
//2.讓main縮放
main.setScaleX(evaluateResult);
main.setScaleY(evaluateResult);
}
private float evaluate(float fraction, float startValue, float endValue) {
return startValue + fraction * (endValue - startValue);
}
...
}