您好,登錄后才能下訂單哦!
Android中怎么利用 ListView實現(xiàn)下拉頂部圖片變大效果,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
變量說明
這里變量包含了:自定義返回動畫加速度、自定義動畫線程、頭部圖片view,最后的y坐標,做好的比例,做大的比例等。
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;//最大的比例 private OnScrollListener mOnScrollListener;//滑動監(jiān)聽 private ScalingRunnalable mScalingRunnalable;//動畫線程 private int mScreenHeight;//屏幕高度 private ImageView mShadow;//陰影遮罩
自定義View初始化:設(shè)置了頭部的頭部和遮罩并且設(shè)置了監(jiān)聽。
/** * 初始化 * @param paramContext */ private void init(Context paramContext) { DisplayMetrics metrics = new DisplayMetrics(); ((Activity) paramContext).getWindowManager().getDefaultDisplay().getMetrics(metrics); this.mScreenHeight = metrics.heightPixels;//屏幕高度賦值 this.mHeaderContainer = new FrameLayout(paramContext);//頭部 this.mHeaderImage = new ImageView(paramContext);//頭部圖片 int screenWidth = metrics.widthPixels;//屏幕寬度 //設(shè)置頭部View的樣式 設(shè)置屏幕寬度,最大樣式高度為屏幕高度的9/16 setHeaderViewSize(screenWidth, (int) (9.0F * (screenWidth / 16.0F))); this.mShadow = new ImageView(paramContext);//遮罩 FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); layoutParams.gravity = Gravity.CENTER; this.mShadow.setLayoutParams(layoutParams);//設(shè)置遮罩樣式 //頭部添加View this.mHeaderContainer.addView(this.mHeaderImage); this.mHeaderContainer.addView(this.mShadow); //添加頭部 addHeaderView(this.mHeaderContainer); //初始化返回動畫 this.mScalingRunnalable = new ScalingRunnalable(); //設(shè)置監(jiān)聽 super.setOnScrollListener(this); }
開啟動畫:判斷當前的頭部布局底部的位置–是否大于圖片的初始化高度。
/** * 開啟動畫 */ private void endScraling() { if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) { Log.d(TAG, "this.mScalingRunnalable.startAnimation(200L)"); this.mScalingRunnalable.startAnimation(200L); } }
多指觸碰時將第0個手指賦值。
/** * 多點觸碰的時候按下,當?shù)?個有手指抬起,再次有手指按下后,將按下的事件的手指指針作為當前手指指針 * * @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); }
重置所有的數(shù)據(jù)
/** * 重置所有數(shù)據(jù) */ 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)) {//如果是向上滑動 int toUpScroll = (int) (0.65D * bottomSpacing); this.mHeaderImage.scrollTo(0, -toUpScroll); Log.d(TAG, "onScroll 向上滑動 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); } }
不同事件處理,修改布局樣式
@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); //獲取當前id的手機指針 int pointer = motionEvent.findPointerIndex(this.mActivePointerId); //判斷指針不為空 if (pointer == INVALID_VALUE) { Log.e(TAG, "Invalid pointerId=" + this.mActivePointerId + " in onTouchEvent"); } else { //如果開始沒有賦值,則需要賦值 if (this.mLastMotionY == INVALID_VALUE) { this.mLastMotionY = motionEvent.getY(pointer); } if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) { //獲取頭部樣式 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)) { //最后比例小于默認并且當前的比例要小于上次的比例,則修改頭部的高度 headerParams.height = this.mHeaderHeight; this.mHeaderContainer.setLayoutParams(headerParams); return super.onTouchEvent(motionEvent); } else { //否則,將當前的比例賦值為最后一次的比例 this.mLastScale = Math.min(Math.max(currentScale, 1.0F), this.mMaxScale); headerParams.height = ((int) (this.mHeaderHeight * this.mLastScale)); //判斷修改后的高度小于屏幕的高度 if (headerParams.height < this.mScreenHeight) { this.mHeaderContainer.setLayoutParams(headerParams); } //記錄最后的y坐標 this.mLastMotionY = motionEvent.getY(pointer); return true; } } this.mLastMotionY = motionEvent.getY(pointer); } break; case MotionEvent.ACTION_UP: Log.d(TAG, "onTouchEvent ACTION_UP 重置"); //重置 reset(); //當手指起來的時候,結(jié)算拉伸,判斷是否開啟動畫 endScraling(); break; case MotionEvent.ACTION_CANCEL: int actionIndex = motionEvent.getActionIndex();//獲取當前最上層的指針 this.mLastMotionY = motionEvent.getY(actionIndex);//獲取最后的y坐標 this.mActivePointerId = motionEvent.getPointerId(actionIndex);//獲取最上層指針的手指 Log.d(TAG, "onTouchEvent ACTION_CANCEL actionIndex = " + actionIndex + " mLastMotionY = " + mLastMotionY + " mActivePointerId = " + mActivePointerId); break; case MotionEvent.ACTION_POINTER_DOWN: //當?shù)诙€手指按下或者放開觸發(fā)這個事件 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: //當?shù)诙€手指按下或者放開 Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_UP "); break; } return super.onTouchEvent(motionEvent); }
向上返回時的動畫
/** * 向上返回的動畫 */ class ScalingRunnalable implements Runnable { long mDuration;//持續(xù)時間 boolean mIsFinished = true;//是否結(jié)束 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;//頭部樣式 //判斷是否中止和已經(jīng)滑動超過的默認大小 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 -- 修改頭部高度"); mHeaderContainerParams.height = PullToZoomListView.this.mHeaderHeight; mHeaderContainerParams.height = ((int) (currentScale * PullToZoomListView.this.mHeaderHeight)); PullToZoomListView.this.mHeaderContainer.setLayoutParams(mHeaderContainerParams); PullToZoomListView.this.post(this);//循環(huán)執(zhí)行 } else { Log.d(TAG, "ScalingRunnalable currentScale < 1.0 -- 中止"); this.mIsFinished = true; } } } public void startAnimation(long paramLong) { Log.d(TAG, "ScalingRunnalable 開始執(zhí)行動畫"); 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); } }
關(guān)于Android中怎么利用 ListView實現(xiàn)下拉頂部圖片變大效果問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。