怎么在Android中通過(guò)自定義View實(shí)現(xiàn)一個(gè)抽屜效果?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。
麟游網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
Android 自定義View實(shí)現(xiàn)抽屜效果
說(shuō)明
主要算法是:動(dòng)畫(huà)當(dāng)前值=起始值+(目標(biāo)值-起始值)*interpolatedTime
其中interpolatedTime是一個(gè)0.0f~1.0f的數(shù)字,系統(tǒng)自己插值計(jì)算好了(默認(rèn)是線性變化的),當(dāng)然你可以自己寫(xiě)插值器
/** * 由于上面不能使用scrollBy,那么這里就不能使用Scroller這個(gè)類來(lái)完成平滑移動(dòng)了,還好我們有動(dòng)畫(huà) */ 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ù)字值),但是不能這樣獲取高度,因?yàn)檫@里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.求第一個(gè)觸點(diǎn)的id, 此時(shí)可能有多個(gè)觸點(diǎn),但至少一個(gè) // 獲取索引為0的手指id mPointerId = event.getPointerId(0); downX = (int) event.getX(); lastX = downX; break; case MotionEvent.ACTION_MOVE: // 獲取當(dāng)前手指id所對(duì)應(yīng)的索引,雖然在ACTION_DOWN的時(shí)候,我們默認(rèn)選取索引為0 // 的手指,但當(dāng)有第二個(gè)手指觸摸,并且先前有效的手指up之后,我們會(huì)調(diào)整有效手指 // 屏幕上可能有多個(gè)手指,我們需要保證使用的是同一個(gè)手指的移動(dòng)軌跡, // 因此此處不能使用event.getActionIndex()來(lái)獲得索引 final int pointerIndex = event.findPointerIndex(mPointerId); moveX = (int) event.getX(pointerIndex); deltaX = moveX - lastX; // 把觸摸移動(dòng)引起的增量,體現(xiàn)在menu和main的左側(cè)left上 menuLeft = (int) (menuLeft + deltaX * 0.43);//讓菜單移動(dòng)的慢一點(diǎn) mainLeft = mainLeft + deltaX; // 讓菜單根據(jù)手指增量移動(dòng),考慮兩側(cè)邊界問(wèn)題(通過(guò)不停地layout實(shí)現(xiàn)移動(dòng)效果) // 為何不適用scrollBy,因?yàn)閟crollBy移動(dòng)的是外層的大View,現(xiàn)在需求是分別移動(dòng)這個(gè)大view內(nèi)的兩個(gè)小View // scrollBy的話,會(huì)讓菜單和主頁(yè)面同時(shí)移動(dòng),不會(huì)產(chǎn)生錯(cuò)位效果, // 你會(huì)想,那讓小view自己scrollBy,這樣也是不行的, // 因?yàn)樽屝iew,例如menu調(diào)用scrollBy的話,會(huì)讓menu自己的邊框在動(dòng), // 看上去,是menu內(nèi)部的文字在移動(dòng),但是menu并沒(méi)有在外層的大View里移動(dòng) // 說(shuō)的很拗口,但是真的不能用scrollBy if (menuLeft >= menuRightBorder) { menuLeft = menuRightBorder; } else if (menuLeft <= menuLeftBorder) { menuLeft = menuLeftBorder; } menuView.layout(menuLeft, 0, menuLeft + menuWidth, menuHeight); // 讓主頁(yè)面根據(jù)手指增量移動(dòng),考慮兩側(cè)邊界問(wèn)題 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.求偽瞬時(shí)速度 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的菜單寬度就打開(kāi)菜單,否則打開(kāi)主頁(yè)面 if (mainLeft > menuWidth / 2.5) { Log.e("qqq", "顯示菜單"); smoothToMenu(); } else { Log.e("qqq", "顯示主頁(yè)面"); smoothToMain(); } } // 4.ACTION_UP釋放VelocityTracker,交給其他控件使用 releaseVelocityTracker(); break; case MotionEvent.ACTION_CANCEL: // 4.ACTION_UP釋放VelocityTracker,交給其他控件使用 releaseVelocityTracker(); case MotionEvent.ACTION_POINTER_UP: // 獲取離開(kāi)屏幕的手指的索引 int pointerIndexLeave = event.getActionIndex(); int pointerIdLeave = event.getPointerId(pointerIndexLeave); if (mPointerId == pointerIdLeave) { // 離開(kāi)屏幕的正是目前的有效手指,此處需要重新調(diào)整,并且需要重置VelocityTracker int reIndex = pointerIndexLeave == 0 ? 1 : 0; mPointerId = event.getPointerId(reIndex); // 調(diào)整觸摸位置,防止出現(xiàn)跳動(dòng) 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),這影響到了,再次手指觸摸時(shí)候的動(dòng)畫(huà),否則突變 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),這影響到了,再次手指觸摸時(shí)候的動(dòng)畫(huà),否則突變 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這個(gè)類來(lái)完成平滑移動(dòng)了,還好我們有動(dòng)畫(huà) */ 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); } } }
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對(duì)創(chuàng)新互聯(lián)的支持。
文章名稱:怎么在Android中通過(guò)自定義View實(shí)現(xiàn)一個(gè)抽屜效果
路徑分享:http://muchs.cn/article40/ipjhho.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航、軟件開(kāi)發(fā)、自適應(yīng)網(wǎng)站、App設(shè)計(jì)、品牌網(wǎng)站設(shè)計(jì)、外貿(mào)建站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)