成人午夜视频全免费观看高清-秋霞福利视频一区二区三区-国产精品久久久久电影小说-亚洲不卡区三一区三区一区

怎么在Android中通過自定義View實(shí)現(xiàn)一個抽屜效果

怎么在Android中通過自定義View實(shí)現(xiàn)一個抽屜效果?很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。

麟游網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、成都響應(yīng)式網(wǎng)站建設(shè)公司等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營維護(hù)。創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。

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

說明

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

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

其中interpolatedTime是一個0.0f~1.0f的數(shù)字,系統(tǒng)自己插值計(jì)算好了(默認(rèn)是線性變化的),當(dā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ù)字值),但是不能這樣獲取高度,因?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.求第一個觸點(diǎn)的id, 此時(shí)可能有多個觸點(diǎn),但至少一個
        // 獲取索引為0的手指id
        mPointerId = event.getPointerId(0);
        downX = (int) event.getX();
        lastX = downX;
        break;

      case MotionEvent.ACTION_MOVE:
// 獲取當(dāng)前手指id所對應(yīng)的索引,雖然在ACTION_DOWN的時(shí)候,我們默認(rèn)選取索引為0
        // 的手指,但當(dāng)有第二個手指觸摸,并且先前有效的手指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);//讓菜單移動的慢一點(diǎn)
        mainLeft = mainLeft + deltaX;
//        讓菜單根據(jù)手指增量移動,考慮兩側(cè)邊界問題(通過不停地layout實(shí)現(xiàn)移動效果)
//        為何不適用scrollBy,因?yàn)閟crollBy移動的是外層的大View,現(xiàn)在需求是分別移動這個大view內(nèi)的兩個小View
//        scrollBy的話,會讓菜單和主頁面同時(shí)移動,不會產(chǎn)生錯位效果,
//        你會想,那讓小view自己scrollBy,這樣也是不行的,
//        因?yàn)樽屝iew,例如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.求偽瞬時(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的菜單寬度就打開菜單,否則打開主頁面

          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 &#63; 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),這影響到了,再次手指觸摸時(shí)候的動畫,否則突變
    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í)候的動畫,否則突變
    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);


    }
  }

}

看完上述內(nèi)容是否對您有幫助呢?如果還想對相關(guān)知識有進(jìn)一步的了解或閱讀更多相關(guān)文章,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝您對創(chuàng)新互聯(lián)的支持。

文章名稱:怎么在Android中通過自定義View實(shí)現(xiàn)一個抽屜效果
路徑分享:http://jinyejixie.com/article40/ipjhho.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供面包屑導(dǎo)航軟件開發(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)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

手機(jī)網(wǎng)站建設(shè)
拉萨市| 汪清县| 宣城市| 秦安县| 白银市| 盐山县| 恩平市| 岗巴县| 长海县| 三门峡市| 五家渠市| 新竹县| 三门县| 海门市| 江阴市| 滨海县| 辽宁省| 三门县| 临猗县| 芒康县| 客服| 吉木乃县| 外汇| 荥经县| 会泽县| 唐河县| 柳州市| 都昌县| 东丰县| 隆回县| 西乌珠穆沁旗| 沽源县| 龙南县| 青海省| 大丰市| 东阿县| 长葛市| 辰溪县| 慈溪市| 江源县| 大连市|