English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Este artículo comparte el código específico de Android ListView que cambia la imagen superior al desplazarse hacia abajo, a modo de ejemplo, para que lo puedan referenciar, el contenido específico es el siguiente
Al ver el código de los grandes gurús en git, descubrí que estaban descompilando código de otros, sin agregar comentarios y el código no estaba completamente compilado, por lo que aquí hice comentarios simples, solo para el aprendizaje.
Descripción de las variables
Aquí las variables incluyen: aceleración de animación personalizada, hilo de animación personalizado, vista de imagen de cabecera, última coordenada y, proporción hecha, proporción aumentada, etc.
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;//Cabecera private int mHeaderHeight;//头部图片的高度 private ImageView mHeaderImage;//Imagen de la cabecera float mLastMotionY = INVALID_VALUE;//最后y坐标 float mLastScale = INVALID_VALUE;//最后的比例 float mMaxScale = INVALID_VALUE;//最大的比例 private OnScrollListener mOnScrollListener;//滑动监听 private ScalingRunnalable mScalingRunnalable;//动画线程 private int mScreenHeight;//屏幕高度 private ImageView mShadow;//阴影遮罩
自定义View初始化:设置了头部的头部和遮罩并且设置了监听。
/** * 初始化 * @param paramContext */ private void init(Context paramContext) { DisplayMetrics metrics = new DisplayMetrics(); ((Activity) paramContext).getWindowManager().getDefaultDisplay().getMetrics(metrics); this.mAlturaPantalla = metrics.heightPixels;//Asignar altura de la pantalla this.mHeaderContainer = new FrameLayout(paramContext);//Cabecera this.mHeaderImage = new ImageView(paramContext);//Imagen de la cabecera int anchoPantalla = metrics.widthPixels;//Ancho de la pantalla //Establecer estilo del View de la cabecera Establecer el ancho de la pantalla, el estilo máximo de altura es la altura de la pantalla9/16 setHeaderViewSize(anchoPantalla, (int) (9.0F * (anchoPantalla / 16.0F))); this.mSombra = new ImageView(paramContext);//Sombra FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); layoutParams.gravity = Gravity.CENTER; this.mSombra.setLayoutParams(layoutParams);//Establecer estilo de la sombra //Agregar View a la cabecera this.mHeaderContainer.addView(this.mHeaderImage); this.mHeaderContainer.addView(this.mSombra); //Agregar cabecera addHeaderView(this.mHeaderContainer); //Inicializar animación de retorno this.mEscalable = new ScalingRunnalable(); //Establecer escucha super.setOnScrollListener(this); }
Iniciar animación: evaluar la posición inferior del diseño de la cabecera actual - ¿es mayor que la altura inicial de la imagen?.
/** * Iniciar animación */ private void finalizarEscalado() { if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) { Log.d(TAG, "esta.mEscalable.startAnimation("200L)"); this.mScalingRunnalable.startAnimation(200L); } }
当多指触碰时将第0个手指赋值。
/** * 当多点触碰时按下,当第0个有手指抬起,再次有手指按下后,将按下的事件的手指指针作为当前手指指针 * * @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); }
重置所有的数据
/** * 重置所有数据 */ private void reset() { this.mActivePointerId = INVALID_VALUE; this.mLastMotionY = INVALID_VALUE; this.mMaxScale = INVALID_VALUE; this.mLastScale = INVALID_VALUE; }
当向上滚动时修改布局样式
@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)) {//Si es deslizamiento hacia arriba int toUpScroll = (int) (0.65D * bottomSpacing); this.mHeaderImage.scrollTo(0, -toUpScroll); Log.d(TAG, "onScroll deslizamiento hacia arriba 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); } }
Manejo de diferentes eventos, modificación del estilo del diseño
@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(); //Obtener el ID del puntero del primer dedo 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); //Obtener el puntero de teléfono actual con el id int pointer = motionEvent.findPointerIndex(this.mActivePointerId); //Determinar si el puntero no está vacío if (pointer == INVALID_VALUE) { Log.e(TAG, "Invalid pointerId=" + this.mActivePointerId + " in onTouchEvent"); } //Si no se ha asignado un valor al inicio,则需要赋值 if (this.mLastMotionY == INVALID_VALUE) { this.mLastMotionY = motionEvent.getY(pointer); } if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) { //Obtener estilo de encabezado 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)) { //Si la última proporción es menor que la proporción predeterminada y la proporción actual es menor que la última proporción, modificar la altura de la cabeza headerParams.height = this.mHeaderHeight; this.mHeaderContainer.setLayoutParams(headerParams); return super.onTouchEvent(motionEvent); } //de lo contrario, asignar la proporción actual como la última proporción this.mLastScale = Math.min(Math.max(currentScale, 1.0F), this.mMaxScale); headerParams.height = ((int) (this.mHeaderHeight * this.mLastScale)); //Determinar si la altura modificada es menor que la altura de la pantalla if (headerParams.height < this.mScreenHeight) { this.mHeaderContainer.setLayoutParams(headerParams); } //Registrar la última coordenada y this.mLastMotionY = motionEvent.getY(pointer); return true; } } this.mLastMotionY = motionEvent.getY(pointer); } break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent ACTION_UP Reiniciar"); //Reiniciar reset(); //Cuando el dedo se levanta, liquidar el estiramiento y determinar si se ha iniciado el animación endScraling(); break; case MotionEvent.ACTION_CANCEL: int actionIndex = motionEvent.getActionIndex();//Obtener el puntero más alto actual this.mLastMotionY = motionEvent.getY(actionIndex);//Obtener la última coordenada y this.mActivePointerId = motionEvent.getPointerId(actionIndex);//Obtener el dedo del puntero más alto Log.d(TAG, "onTouchEvent ACTION_CANCEL actionIndex = ") + actionIndex + " mLastMotionY = " + mLastMotionY + " mActivePointerId = " + mActivePointerId); break; case MotionEvent.ACTION_POINTER_DOWN: //当第二个手指按下或者放开触发这个事件 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 -- Modificar la altura de la cabecera"); mHeaderContainerParams.height = PullToZoomListView.this.mHeaderHeight; mHeaderContainerParams.height = ((int) (currentScale * PullToZoomListView.this.mHeaderHeight)); PullToZoomListView.this.mHeaderContainer.setLayoutParams(mHeaderContainerParams); PullToZoomListView.this.post(this);//Ejecución en bucle } Log.d(TAG, "ScalingRunnalable currentScale < 1.0 -- Interrupción"); this.mIsFinished = true; } } } public void startAnimation(long paramLong) { Log.d(TAG, "ScalingRunnalable 开始执行动画"); 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); } }
Esto es todo el contenido de este artículo, espero que ayude a su aprendizaje y que todos apoyen a la tutoría de gritos.
Declaración: El contenido de este artículo se obtiene de la red, es propiedad del autor original, el contenido se contribuye y carga de manera autónoma por los usuarios de Internet, este sitio no posee los derechos de propiedad, no se ha editado artificialmente y no asume responsabilidad por las responsabilidades legales relacionadas. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, por favor reemplace # con @) para denunciar y proporcionar evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.