国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 自定義View實現抽屜效果

2019-10-23 18:28:52
字體:
來源:轉載
供稿:網友

Android 自定義View實現抽屜效果

說明

  1. 這個自定義View,沒有處理好多點觸摸問題
  2. View跟著手指移動,沒有采用傳統的scrollBy方法,而是通過不停地重新布局子View的方式,來使得子View產生滾動效果menuView.layout(menuLeft, 0, menuLeft + menuWidth, menuHeight);
  3. 相應的,由于沒有使用scrollBy方法,就沒有產生getScrollX值,所以不能通過Scroller的startScroll方法來完成手指離開后的平滑滾動效果,而是使用了Animation動畫的applyTransformation方法來完成插值,從而實現動畫效果

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

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

 /**   * 由于上面不能使用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的正確寬度(只能獲取具體的數字值),但是不能這樣獲取高度,因為這里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所對應的索引,雖然在ACTION_DOWN的時候,我們默認選取索引為0        // 的手指,但當有第二個手指觸摸,并且先前有效的手指up之后,我們會調整有效手指        // 屏幕上可能有多個手指,我們需要保證使用的是同一個手指的移動軌跡,        // 因此此處不能使用event.getActionIndex()來獲得索引        final int pointerIndex = event.findPointerIndex(mPointerId);        moveX = (int) event.getX(pointerIndex);        deltaX = moveX - lastX;//        把觸摸移動引起的增量,體現在menu和main的左側left上        menuLeft = (int) (menuLeft + deltaX * 0.43);//讓菜單移動的慢一點        mainLeft = mainLeft + deltaX;//        讓菜單根據手指增量移動,考慮兩側邊界問題(通過不停地layout實現移動效果)//        為何不適用scrollBy,因為scrollBy移動的是外層的大View,現在需求是分別移動這個大view內的兩個小View//        scrollBy的話,會讓菜單和主頁面同時移動,不會產生錯位效果,//        你會想,那讓小view自己scrollBy,這樣也是不行的,//        因為讓小view,例如menu調用scrollBy的話,會讓menu自己的邊框在動,//        看上去,是menu內部的文字在移動,但是menu并沒有在外層的大View里移動//        說的很拗口,但是真的不能用scrollBy        if (menuLeft >= menuRightBorder) {          menuLeft = menuRightBorder;        } else if (menuLeft <= menuLeftBorder) {          menuLeft = menuLeftBorder;        }        menuView.layout(menuLeft, 0, menuLeft + menuWidth, menuHeight);//        讓主頁面根據手指增量移動,考慮兩側邊界問題        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) {          // 離開屏幕的正是目前的有效手指,此處需要重新調整,并且需要重置VelocityTracker          int reIndex = pointerIndexLeave == 0 ? 1 : 0;          mPointerId = event.getPointerId(reIndex);          // 調整觸摸位置,防止出現跳動          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的左側狀態,這影響到了,再次手指觸摸時候的動畫,否則突變    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的左側狀態,這影響到了,再次手指觸摸時候的動畫,否則突變    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);    }  }}

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


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 凤凰县| 阿拉尔市| 什邡市| 廊坊市| 奇台县| 秭归县| 旅游| 汉沽区| 长丰县| 海口市| 平利县| 且末县| 清涧县| 丹棱县| 永善县| 黄龙县| 太和县| 苍梧县| 依兰县| 西宁市| 大宁县| 佳木斯市| 凤冈县| 永清县| 堆龙德庆县| 金华市| 邵阳市| 治多县| 长顺县| 嘉禾县| 南陵县| 白银市| 卓尼县| 乡城县| 调兵山市| 会泽县| 海丰县| 海丰县| 政和县| 清丰县| 图们市|