English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Implementazione dell'effetto di ingrandimento della foto in alto nella ListView Android

Questo esempio condiviso condivide il codice specifico per Android ListView che cambia la dimensione dell'immagine in alto trascinando verso il basso, che può essere consultato come riferimento, il contenuto specifico è il seguente

Sulla piattaforma git ho trovato il codice di altri decompilato, senza commenti e il codice non è stato completamente compilato, quindi ho aggiunto un'annotazione semplice, che serve solo per imparare.

Spiegazione delle variabili

Questa variabile include: accelerazione dell'animazione di ritorno personalizzata, thread dell'animazione personalizzata, ImageView della testa, coordinate y finali, rapporto finale, ecc.

private static final String TAG = "PullToZoomListView";
 private static final int INVALID_VALUE = -1;//重置值
 //自定义加速度动画
 private static final Interpolator sInterpolator = new Interpolator() {
  public float getInterpolation(float interpolator) {
   float f = interpolator - 1.0F;
   return 1.0F + f * (f * (f * (f * f)));
  }
 };
 private int mActivePointerId = INVALID_VALUE;//当前手指的Id
 private FrameLayout mHeaderContainer;//头部
 private int mHeaderHeight;//头部图片的高度
 private ImageView mHeaderImage;//头部图片
 float mLastMotionY = INVALID_VALUE;//最后y坐标
 float mLastScale = INVALID_VALUE;//最后的比例
 float mMaxScale = INVALID_VALUE;//rapporto massimo
 private OnScrollListener mOnScrollListener;//ascoltatore scorrevole
 private ScalingRunnalable mScalingRunnalable;//线程 animazione
 private int mScreenHeight;//altezza dello schermo
 private ImageView mShadow;//ombra di copertura

inizializzazione della View personalizzata: è stato impostato il header della testa e l'ombra e impostato l'ascoltatore.

/**
  * inizializzazione
  * @param paramContext
  */
 private void init(Context paramContext) {
  DisplayMetrics metrics = new DisplayMetrics();
  ((Activity) paramContext).getWindowManager().getDefaultDisplay().getMetrics(metrics);
  this.mScreenHeight = metrics.heightPixels;//assegnare altezza dello schermo
  this.mHeaderContainer = new FrameLayout(paramContext);//testa
  this.mHeaderImage = new ImageView(paramContext);//immagine di testa
  int screenWidth = metrics.widthPixels;//larghezza dello schermo
  //impostare lo stile del View di testa Impostare la larghezza dello schermo, l'altezza massima dello stile è 9/16 dell'altezza dello schermo
  setHeaderViewSize(screenWidth, (int) (9.0F * (screenWidth / 16.0F)));
  this.mShadow = new ImageView(paramContext);//ombra
  FrameLayout.LayoutParams layoutParams =
    new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
      ViewGroup.LayoutParams.MATCH_PARENT);
  layoutParams.gravity = Gravity.CENTER;
  this.mShadow.setLayoutParams(layoutParams);// Imposta lo stile dello schermo di copertura
  // Aggiungi View alla testa
  this.mHeaderContainer.addView(this.mHeaderImage);
  this.mHeaderContainer.addView(this.mShadow);
  // Aggiungi la testa
  addHeaderView(this.mHeaderContainer);
  // Inizializza l'animazione di ritorno
  this.mScalingRunnalable = new ScalingRunnalable();
  // Imposta l'ascoltatore
  super.setOnScrollListener(this);
 }

Avvia l'animazione: verifica la posizione inferiore della layout corrente - se è maggiore dell'altezza iniziale dell'immagine.

/**
  * Avvia l'animazione
  */
 private void endScraling() {
  if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
   Log.d(TAG, "this.mScalingRunnalable.startAnimation(200L)");
   this.mScalingRunnalable.startAnimation(200L);
  }
 }

Assegnare il primo dito quando si tocca più dita.

/**
  * Quando si tocca più volte, quando il primo dito si solleva e poi un altro dito viene premuto, l'indice del dito premuto viene utilizzato come puntatore attuale
  *
  * @param motionEvent
  */
 private void onSecondaryPointerUp(MotionEvent motionEvent) {
  Log.d(TAG, "onSecondaryPointerUp motionEvent.getPointerId(0) = " + motionEvent.getPointerId(0));
  Log.d(TAG, "onSecondaryPointerUp this.mActivePointerId = " + this.mActivePointerId);
  if (motionEvent.getPointerId(0) == this.mActivePointerId) {
   this.mLastMotionY = motionEvent.getY(0);
   this.mActivePointerId = motionEvent.getPointerId(0);
  }
  Log.d(TAG, "onSecondaryPointerUp mLastMotionY = " + mLastMotionY);
  Log.d(TAG, "onSecondaryPointerUp mActivePointerId = " + mActivePointerId);
 }

Resetta tutti i dati

/**
 * Resetta tutti i dati
*/
 private void reset() {
  this.mActivePointerId = INVALID_VALUE;
  this.mLastMotionY = INVALID_VALUE;
  this.mMaxScale = INVALID_VALUE;
  this.mLastScale = INVALID_VALUE;
 }

Modifica lo stile del layout quando si scrolla verso l'alto

@Override
 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
  Log.d(TAG, "onScroll");
  float bottomSpacing = this.mHeaderHeight - this.mHeaderContainer.getBottom();
  Log.d(TAG, "onScroll bottomSpacing = " + bottomSpacing);
  if ((bottomSpacing > 0.0F) && (bottomSpacing < this.mHeaderHeight)) { // Se si scorre verso l'alto
   int toUpScroll = (int) (0.65D * bottomSpacing);
   this.mHeaderImage.scrollTo(0, -toUpScroll);
   Log.d(TAG, "onScroll Scorrendo verso l'alto toUpScroll = " + toUpScroll);
  } else if (this.mHeaderImage.getScrollY() != 0) {
   Log.d(TAG, "onScroll this.mHeaderImage.getScrollY() = " + this.mHeaderImage.getScrollY());
   this.mHeaderImage.scrollTo(0, 0);
  }
  if (this.mOnScrollListener != null) {
   this.mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
  }
 }

Gestione degli eventi diversi, modifica lo stile del layout

@Override
 public boolean onTouchEvent(MotionEvent motionEvent) {
  switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
   case MotionEvent.ACTION_OUTSIDE:
   case MotionEvent.ACTION_DOWN:
    if (!this.mScalingRunnalable.mIsFinished) {
     this.mScalingRunnalable.abortAnimation();
    }
    this.mLastMotionY = motionEvent.getY();
    //获取第一个手指指针的ID
    this.mActivePointerId = motionEvent.getPointerId(0);
    this.mMaxScale = (this.mScreenHeight / this.mHeaderHeight);
    this.mLastScale = (this.mHeaderContainer.getBottom() / this.mHeaderHeight);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mLastMotionY = " + mLastMotionY);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mActivePointerId = " + mActivePointerId);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mMaxScale = " + mMaxScale);
    Log.d(TAG, "onTouchEvent ACTION_DOWN mLastScale = " + mLastScale);
    break;
   case MotionEvent.ACTION_MOVE:
    Log.d(TAG, "onTouchEvent ACTION_MOVE mActivePointerId" + mActivePointerId);
    //Ottieni il puntatore del telefono con l'id corrente
    int pointer = motionEvent.findPointerIndex(this.mActivePointerId);
    //Verifica che il puntatore non sia vuoto
    if (pointer == INVALID_VALUE) {
     Log.e(TAG, "Invalid pointerId=" + this.mActivePointerId + " in onTouchEvent");
    } else {
     //Se non è stato assegnato all'inizio,则需要 assegnarlo
     if (this.mLastMotionY == INVALID_VALUE) {
      this.mLastMotionY = motionEvent.getY(pointer);
     }
     if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
      //Ottieni lo stile dell'intestazione
      ViewGroup.LayoutParams headerParams = this.mHeaderContainer.getLayoutParams();
      float currentScale = ((motionEvent.getY(pointer) - this.mLastMotionY + this.mHeaderContainer.getBottom())
        / this.mHeaderHeight - this.mLastScale)
        / 2.0F + this.mLastScale;
      if ((this.mLastScale <= 1.0D) && (currentScale < this.mLastScale)) {
       //Se l'ultima proporzionalità è minore della predefinita e la proporzionalità corrente è minore dell'ultima proporzionalità, modifica l'altezza dell'intestazione
       headerParams.height = this.mHeaderHeight;
       this.mHeaderContainer.setLayoutParams(headerParams);
       return super.onTouchEvent(motionEvent);
      } else {
       //Altrimenti, assegna la proporzionalità corrente come l'ultima proporzionalità
       this.mLastScale = Math.min(Math.max(currentScale, 1.0F), this.mMaxScale);
       headerParams.height = ((int) (this.mHeaderHeight * this.mLastScale));
       //verifica se l'altezza modificata è inferiore all'altezza dello schermo
       if (headerParams.height < this.mScreenHeight) {
        this.mHeaderContainer.setLayoutParams(headerParams);
       }
       //registra l'ultima coordinata y
       this.mLastMotionY = motionEvent.getY(pointer);
       return true;
      }
     }
     this.mLastMotionY = motionEvent.getY(pointer);
    }
    break;
   case MotionEvent.ACTION_UP:
    Log.d(TAG, "onTouchEvent ACTION_UP ripristina");
    //ripristina
    reset();
    //quando il dito si solleva, calcola la trazione, determina se è stato attivato l'animazione
    endScraling();
    break;
   case MotionEvent.ACTION_CANCEL:
    int actionIndex = motionEvent.getActionIndex();//ottieni il puntatore più alto attualmente
    this.mLastMotionY = motionEvent.getY(actionIndex);//ottieni l'ultima coordinata y
    this.mActivePointerId = motionEvent.getPointerId(actionIndex);//ottieni il dito del puntatore più alto
    Log.d(TAG, "onTouchEvent ACTION_CANCEL actionIndex = " + actionIndex + " mLastMotionY = " + mLastMotionY + " mActivePointerId = " + mActivePointerId);
    break;
   case MotionEvent.ACTION_POINTER_DOWN:
    //quando il secondo dito viene premuto o rilasciato viene scatenato questo evento
    onSecondaryPointerUp(motionEvent);
    this.mLastMotionY = motionEvent.getY(motionEvent.findPointerIndex(this.mActivePointerId));
    Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_DOWN mLastMotionY = " + mLastMotionY);
    break;
   case MotionEvent.ACTION_POINTER_UP:
    //当第二个手指按下或者放开
    Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_UP ");
    break;
  }
  return super.onTouchEvent(motionEvent);
 }

* 向上返回时的动画

/**
  * 向上返回的动画
  */
 class ScalingRunnalable implements Runnable {
  long mDuration;//持续时间
  boolean mIsFinished = true;//是否结束
  float mScale;//比例
  long mStartTime;//开始时间
  ScalingRunnalable() {
  }
  /**
   * 中止动画
   */
  public void abortAnimation() {
   this.mIsFinished = true;
  }
  /**
   * 是否中止
   *
   * @return
   */
  public boolean isFinished() {
   return this.mIsFinished;
  }
  public void run() {
   Log.d(TAG, "ScalingRunnalable mIsFinished = " + this.mIsFinished + " this.mScale = " + this.mScale);
   float currentScale;
   ViewGroup.LayoutParams mHeaderContainerParams;//头部样式
   //判断是否中止和已经滑动超过的默认大小
   if ((!this.mIsFinished) && (this.mScale > 1.0D)) {
    float currentTime = ((float) SystemClock.currentThreadTimeMillis() - (float) this.mStartTime) / (float) this.mDuration;
    currentScale = this.mScale - (this.mScale - 1.0F) * PullToZoomListView.sInterpolator.getInterpolation(currentTime);
    Log.d(TAG, "ScalingRunnalable currentTime = " + currentTime + " currentScale = " + currentScale);
    mHeaderContainerParams = PullToZoomListView.this.mHeaderContainer.getLayoutParams();
    if (currentScale > 1.0F) {
     Log.d(TAG, "ScalingRunnalable currentScale > 1.0 -- modifica altezza testa");
     mHeaderContainerParams.height = PullToZoomListView.this.mHeaderHeight;
     mHeaderContainerParams.height = ((int) (currentScale * PullToZoomListView.this.mHeaderHeight));
     PullToZoomListView.this.mHeaderContainer.setLayoutParams(mHeaderContainerParams);
     PullToZoomListView.this.post(this);// esegue in loop
    } else {
     Log.d(TAG, "ScalingRunnalable currentScale < 1.0 -- interrotto");
     this.mIsFinished = true;
    }
   }
  }
  public void startAnimation(long paramLong) {
   Log.d(TAG, "ScalingRunnalable inizia l'animazione");
   this.mStartTime = SystemClock.currentThreadTimeMillis();
   this.mDuration = paramLong;
   this.mScale = ((float) (PullToZoomListView.this.mHeaderContainer.getBottom()) / PullToZoomListView.this.mHeaderHeight);
   this.mIsFinished = false;
   Log.d(TAG, "ScalingRunnalable this.mStartTime = " + this.mStartTime);
   Log.d(TAG, "ScalingRunnalable this.mDuration = " + this.mDuration);
   Log.d(TAG, "ScalingRunnalable this.mScale = " + this.mScale);
   Log.d(TAG, "ScalingRunnalable this.mIsFinished = " + this.mIsFinished);
   PullToZoomListView.this.post(this);
  }
 }

Questo è tutto il contenuto dell'articolo, spero che sia utile per la tua apprendimento, e spero che tu sostenga e gridi tutorial.

Dichiarazione: il contenuto di questo articolo è stato tratto da Internet, è di proprietà del rispettivo proprietario, il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, questo sito non detiene il diritto di proprietà, non è stato elaborato manualmente e non assume alcuna responsabilità legale. Se trovi contenuti sospetti di copyright, invia un'e-mail a: notice#oldtoolbag.com (al momento dell'invio dell'e-mail, sostituisci # con @) per segnalare e fornire prove pertinenti. Una volta verificata, questo sito eliminerà immediatamente i contenuti sospetti di copyright.

Ti potrebbe interessare