日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android中仿qq最新版抽屉,Android 自定义View实现抽屉效果

發(fā)布時間:2025/4/5 Android 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android中仿qq最新版抽屉,Android 自定义View实现抽屉效果 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Android 自定義View實現(xiàn)抽屜效果

說明

這個自定義View,沒有處理好多點觸摸問題

View跟著手指移動,沒有采用傳統(tǒng)的scrollBy方法,而是通過不停地重新布局子View的方式,來使得子View產(chǎn)生滾動效果menuView.layout(menuLeft, 0, menuLeft + menuWidth, menuHeight);

相應(yīng)的,由于沒有使用scrollBy方法,就沒有產(chǎn)生getScrollX值,所以不能通過Scroller的startScroll方法來完成手指離開后的平滑滾動效果,而是使用了Animation動畫的applyTransformation方法來完成插值,從而實現(xiàn)動畫效果

主要算法是:動畫當前值=起始值+(目標值-起始值)*interpolatedTime

其中interpolatedTime是一個0.0f~1.0f的數(shù)字,系統(tǒng)自己插值計算好了(默認是線性變化的),當然你可以自己寫插值器

/**

* 由于上面不能使用scrollBy,那么這里就不能使用Scroller這個類來完成平滑移動了,還好我們有動畫

*/

class MyAnimation extends Animation {

private int viewCurrentLfet;

private int viewStartLfet;

private int viewTargetLfet;

private int viewWidth;

private View view;

private int cha;

public MyAnimation(View view, int viewStartLfet, int viewTargetLfet, int viewWidth) {

this.view = view;

this.viewStartLfet = viewStartLfet;

this.viewTargetLfet = viewTargetLfet;

this.viewWidth = viewWidth;

cha = viewTargetLfet - viewStartLfet;

setDuration(Math.abs(cha));

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

super.applyTransformation(interpolatedTime, t);

viewCurrentLfet = (int) (viewStartLfet + cha * interpolatedTime);

view.layout(viewCurrentLfet, 0, viewCurrentLfet + viewWidth, menuHeight);

}

}

完整代碼

package com.sunshine.choutidemo;

import android.content.Context;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.VelocityTracker;

import android.view.View;

import android.view.ViewConfiguration;

import android.view.ViewGroup;

import android.view.animation.Animation;

import android.view.animation.AnimationSet;

import android.view.animation.Transformation;

/**

* Created by a on 2016/8/15.

*/

public class ChouTiView extends ViewGroup {

private View mainView;

private View menuView;

private int menuWidth;

private int downX;

private int lastX;

private int moveX;

private int deltaX;

private int menuLeft;

private int mainLeft;

private int menuHeight;

private int mainWidth;

private int mainHeight;

private int menuLeftBorder;

private int mainLeftBorder;

private int menuRightBorder;

private int mainRightBorder;

private int mMaxVelocity;

private VelocityTracker mVelocityTracker;

private int mPointerId;

private float velocityX;

private float velocityY;

public ChouTiView(Context context) {

super(context);

init();

}

public ChouTiView(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

private void init() {

// 0.獲得此次最大速率

mMaxVelocity = ViewConfiguration.get(getContext()).getMaximumFlingVelocity();

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mainView.measure(widthMeasureSpec, heightMeasureSpec);

menuView.measure(widthMeasureSpec, heightMeasureSpec);

// 獲得子View的正確寬度(只能獲取具體的數(shù)字值),但是不能這樣獲取高度,因為這里match—parent為-1

menuWidth = menuView.getLayoutParams().width;

menuLeft = (int) (-menuWidth * 0.5);

menuLeftBorder = (int) (-menuWidth * 0.5);

menuRightBorder = 0;

mainLeft = 0;

mainLeftBorder = 0;

mainRightBorder = menuWidth;

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

menuHeight = b;

mainWidth = r;

mainHeight = b;

mainView.layout(l, t, r, b);

menuView.layout(menuLeft, t, menuLeft + menuWidth, b);

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

mainView = getChildAt(1);

menuView = getChildAt(0);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

final int action = event.getActionMasked();

acquireVelocityTracker(event); //1.向VelocityTracker添加MotionEvent

final VelocityTracker verTracker = mVelocityTracker;

switch (action) {

case MotionEvent.ACTION_DOWN:

//2.求第一個觸點的id, 此時可能有多個觸點,但至少一個

// 獲取索引為0的手指id

mPointerId = event.getPointerId(0);

downX = (int) event.getX();

lastX = downX;

break;

case MotionEvent.ACTION_MOVE:

// 獲取當前手指id所對應(yīng)的索引,雖然在ACTION_DOWN的時候,我們默認選取索引為0

// 的手指,但當有第二個手指觸摸,并且先前有效的手指up之后,我們會調(diào)整有效手指

// 屏幕上可能有多個手指,我們需要保證使用的是同一個手指的移動軌跡,

// 因此此處不能使用event.getActionIndex()來獲得索引

final int pointerIndex = event.findPointerIndex(mPointerId);

moveX = (int) event.getX(pointerIndex);

deltaX = moveX - lastX;

// 把觸摸移動引起的增量,體現(xiàn)在menu和main的左側(cè)left上

menuLeft = (int) (menuLeft + deltaX * 0.43);//讓菜單移動的慢一點

mainLeft = mainLeft + deltaX;

// 讓菜單根據(jù)手指增量移動,考慮兩側(cè)邊界問題(通過不停地layout實現(xiàn)移動效果)

// 為何不適用scrollBy,因為scrollBy移動的是外層的大View,現(xiàn)在需求是分別移動這個大view內(nèi)的兩個小View

// scrollBy的話,會讓菜單和主頁面同時移動,不會產(chǎn)生錯位效果,

// 你會想,那讓小view自己scrollBy,這樣也是不行的,

// 因為讓小view,例如menu調(diào)用scrollBy的話,會讓menu自己的邊框在動,

// 看上去,是menu內(nèi)部的文字在移動,但是menu并沒有在外層的大View里移動

// 說的很拗口,但是真的不能用scrollBy

if (menuLeft >= menuRightBorder) {

menuLeft = menuRightBorder;

} else if (menuLeft <= menuLeftBorder) {

menuLeft = menuLeftBorder;

}

menuView.layout(menuLeft, 0, menuLeft + menuWidth, menuHeight);

// 讓主頁面根據(jù)手指增量移動,考慮兩側(cè)邊界問題

if (mainLeft >= mainRightBorder) {

mainLeft = mainRightBorder;

} else if (mainLeft <= mainLeftBorder) {

mainLeft = mainLeftBorder;

}

mainView.layout(mainLeft, 0, mainLeft + mainWidth, mainHeight);

lastX = moveX;

break;

case MotionEvent.ACTION_UP:

//3.求偽瞬時速度

verTracker.computeCurrentVelocity(1000, mMaxVelocity);

velocityX = verTracker.getXVelocity(mPointerId);

Log.e("qwe", velocityX + "/" + mMaxVelocity);

if (velocityX > 1000) {

smoothToMenu();

} else if (velocityX < -2000) {

smoothToMain();

} else {

// 判斷松手的位置,如果大于1/2.5的菜單寬度就打開菜單,否則打開主頁面

if (mainLeft > menuWidth / 2.5) {

Log.e("qqq", "顯示菜單");

smoothToMenu();

} else {

Log.e("qqq", "顯示主頁面");

smoothToMain();

}

}

// 4.ACTION_UP釋放VelocityTracker,交給其他控件使用

releaseVelocityTracker();

break;

case MotionEvent.ACTION_CANCEL:

// 4.ACTION_UP釋放VelocityTracker,交給其他控件使用

releaseVelocityTracker();

case MotionEvent.ACTION_POINTER_UP:

// 獲取離開屏幕的手指的索引

int pointerIndexLeave = event.getActionIndex();

int pointerIdLeave = event.getPointerId(pointerIndexLeave);

if (mPointerId == pointerIdLeave) {

// 離開屏幕的正是目前的有效手指,此處需要重新調(diào)整,并且需要重置VelocityTracker

int reIndex = pointerIndexLeave == 0 ? 1 : 0;

mPointerId = event.getPointerId(reIndex);

// 調(diào)整觸摸位置,防止出現(xiàn)跳動

downX = (int) event.getX(reIndex);

// y = event.getY(reIndex);

releaseVelocityTracker();

}

releaseVelocityTracker();

break;

}

return true;

}

private void smoothToMain() {

MyAnimation menuAnimation = new MyAnimation(menuView, menuLeft, menuLeftBorder, menuWidth);

MyAnimation mainAnimation = new MyAnimation(mainView, mainLeft, mainLeftBorder, mainWidth);

AnimationSet animationSet = new AnimationSet(true);

animationSet.addAnimation(menuAnimation);

animationSet.addAnimation(mainAnimation);

startAnimation(animationSet);

//一定記得更新menu和main的左側(cè)狀態(tài),這影響到了,再次手指觸摸時候的動畫,否則突變

menuLeft = menuLeftBorder;

mainLeft = mainLeftBorder;

}

private void smoothToMenu() {

MyAnimation menuAnimation = new MyAnimation(menuView, menuLeft, menuRightBorder, menuWidth);

MyAnimation mainAnimation = new MyAnimation(mainView, mainLeft, mainRightBorder, mainWidth);

AnimationSet animationSet = new AnimationSet(true);

animationSet.addAnimation(menuAnimation);

animationSet.addAnimation(mainAnimation);

startAnimation(animationSet);

//一定記得更新menu和main的左側(cè)狀態(tài),這影響到了,再次手指觸摸時候的動畫,否則突變

menuLeft = menuRightBorder;

mainLeft = mainRightBorder;

}

/**

* @param event 向VelocityTracker添加MotionEvent

* @see android.view.VelocityTracker#obtain()

* @see android.view.VelocityTracker#addMovement(MotionEvent)

*/

private void acquireVelocityTracker(final MotionEvent event) {

if (null == mVelocityTracker) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(event);

}

/**

* 釋放VelocityTracker

*

* @see android.view.VelocityTracker#clear()

* @see android.view.VelocityTracker#recycle()

*/

private void releaseVelocityTracker() {

if (null != mVelocityTracker) {

mVelocityTracker.clear();

mVelocityTracker.recycle();

mVelocityTracker = null;

}

}

/**

* 由于上面不能使用scrollBy,那么這里就不能使用Scroller這個類來完成平滑移動了,還好我們有動畫

*/

class MyAnimation extends Animation {

private int viewCurrentLfet;

private int viewStartLfet;

private int viewTargetLfet;

private int viewWidth;

private View view;

private int cha;

public MyAnimation(View view, int viewStartLfet, int viewTargetLfet, int viewWidth) {

this.view = view;

this.viewStartLfet = viewStartLfet;

this.viewTargetLfet = viewTargetLfet;

this.viewWidth = viewWidth;

cha = viewTargetLfet - viewStartLfet;

setDuration(Math.abs(cha));

}

@Override

protected void applyTransformation(float interpolatedTime, Transformation t) {

super.applyTransformation(interpolatedTime, t);

viewCurrentLfet = (int) (viewStartLfet + cha * interpolatedTime);

view.layout(viewCurrentLfet, 0, viewCurrentLfet + viewWidth, menuHeight);

}

}

}

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

總結(jié)

以上是生活随笔為你收集整理的android中仿qq最新版抽屉,Android 自定义View实现抽屉效果的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。