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