Android ListView實(shí)現(xiàn)下拉頂部圖片變大效果
本文實(shí)例為大家分享了Android ListView下拉頂部圖片變大的具體代碼,供大家參考,具體內(nèi)容如下
在git上查看牛人的代碼,發(fā)現(xiàn)是反編譯別人的代碼,還沒加注釋,代碼也沒有完全編譯完整,所以這里我做的簡單的注釋,僅供學(xué)習(xí)。
變量說明
這里變量包含了:自定義返回動(dòng)畫加速度、自定義動(dòng)畫線程、頭部圖片view,最后的y坐標(biāo),做好的比例,做大的比例等。
private static final String TAG = "PullToZoomListView";
private static final int INVALID_VALUE = -1;//重置值
//自定義加速度動(dòng)畫
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;//當(dāng)前手指的Id
private FrameLayout mHeaderContainer;//頭部
private int mHeaderHeight;//頭部圖片的高度
private ImageView mHeaderImage;//頭部圖片
float mLastMotionY = INVALID_VALUE;//最后y坐標(biāo)
float mLastScale = INVALID_VALUE;//最后的比例
float mMaxScale = INVALID_VALUE;//最大的比例
private OnScrollListener mOnScrollListener;//滑動(dòng)監(jiān)聽
private ScalingRunnalable mScalingRunnalable;//動(dòng)畫線程
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);
//初始化返回動(dòng)畫
this.mScalingRunnalable = new ScalingRunnalable();
//設(shè)置監(jiān)聽
super.setOnScrollListener(this);
}
開啟動(dòng)畫:判斷當(dāng)前的頭部布局底部的位置–是否大于圖片的初始化高度。
/**
* 開啟動(dòng)畫
*/
private void endScraling() {
if (this.mHeaderContainer.getBottom() >= this.mHeaderHeight) {
Log.d(TAG, "this.mScalingRunnalable.startAnimation(200L)");
this.mScalingRunnalable.startAnimation(200L);
}
}
多指觸碰時(shí)將第0個(gè)手指賦值。
/**
* 多點(diǎn)觸碰的時(shí)候按下,當(dāng)?shù)?個(gè)有手指抬起,再次有手指按下后,將按下的事件的手指指針作為當(dāng)前手指指針
*
* @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;
}
向上滾動(dòng)時(shí)修改布局樣式
@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)) {//如果是向上滑動(dòng)
int toUpScroll = (int) (0.65D * bottomSpacing);
this.mHeaderImage.scrollTo(0, -toUpScroll);
Log.d(TAG, "onScroll 向上滑動(dòng) 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();
//獲取第一個(gè)手指指針的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);
//獲取當(dāng)前id的手機(jī)指針
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)) {
//最后比例小于默認(rèn)并且當(dāng)前的比例要小于上次的比例,則修改頭部的高度
headerParams.height = this.mHeaderHeight;
this.mHeaderContainer.setLayoutParams(headerParams);
return super.onTouchEvent(motionEvent);
} else {
//否則,將當(dāng)前的比例賦值為最后一次的比例
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坐標(biāo)
this.mLastMotionY = motionEvent.getY(pointer);
return true;
}
}
this.mLastMotionY = motionEvent.getY(pointer);
}
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "onTouchEvent ACTION_UP 重置");
//重置
reset();
//當(dāng)手指起來的時(shí)候,結(jié)算拉伸,判斷是否開啟動(dòng)畫
endScraling();
break;
case MotionEvent.ACTION_CANCEL:
int actionIndex = motionEvent.getActionIndex();//獲取當(dāng)前最上層的指針
this.mLastMotionY = motionEvent.getY(actionIndex);//獲取最后的y坐標(biāo)
this.mActivePointerId = motionEvent.getPointerId(actionIndex);//獲取最上層指針的手指
Log.d(TAG, "onTouchEvent ACTION_CANCEL actionIndex = " + actionIndex + " mLastMotionY = " + mLastMotionY + " mActivePointerId = " + mActivePointerId);
break;
case MotionEvent.ACTION_POINTER_DOWN:
//當(dāng)?shù)诙€(gè)手指按下或者放開觸發(fā)這個(gè)事件
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:
//當(dāng)?shù)诙€(gè)手指按下或者放開
Log.d(TAG, "onTouchEvent_Po ACTION_POINTER_UP ");
break;
}
return super.onTouchEvent(motionEvent);
}
向上返回時(shí)的動(dòng)畫
/**
* 向上返回的動(dòng)畫
*/
class ScalingRunnalable implements Runnable {
long mDuration;//持續(xù)時(shí)間
boolean mIsFinished = true;//是否結(jié)束
float mScale;//比例
long mStartTime;//開始時(shí)間
ScalingRunnalable() {
}
/**
* 中止動(dòng)畫
*/
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)滑動(dòng)超過的默認(rèn)大小
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í)行動(dòng)畫");
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);
}
}
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android ExpandableListView實(shí)現(xiàn)下拉刷新和加載更多效果
- android使用SwipeRefreshLayout實(shí)現(xiàn)ListView下拉刷新上拉加載
- android使用PullToRefresh框架實(shí)現(xiàn)ListView下拉刷新上拉加載更多
- android ListView結(jié)合xutils3仿微信實(shí)現(xiàn)下拉加載更多
- Android中ListView下拉刷新的實(shí)現(xiàn)代碼
- Android自定義漸變式炫酷ListView下拉刷新動(dòng)畫
- Android ListView實(shí)現(xiàn)上拉加載下拉刷新和滑動(dòng)刪除功能
- Android自定義listview布局實(shí)現(xiàn)上拉加載下拉刷新功能
- Android XListView下拉刷新和上拉加載更多
- Android自定義控件ListView下拉刷新的代碼
相關(guān)文章
android listview優(yōu)化幾種寫法詳細(xì)介紹
這篇文章只是總結(jié)下getView里面優(yōu)化視圖的幾種寫法,需要的朋友可以參考下2012-11-11
Android手機(jī)衛(wèi)士之綁定sim卡序列號(hào)
這篇文章主要介紹了Android手機(jī)衛(wèi)士之綁定sim卡序列號(hào)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
android中ProgressDialog與ProgressBar的使用詳解
本篇文章是對(duì)android中ProgressDialog與ProgressBar的使用進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Android中okhttp3.4.1+retrofit2.1.0實(shí)現(xiàn)離線緩存
這篇文章主要介紹了Android中okhttp3.4.1結(jié)合retrofit2.1.0實(shí)現(xiàn)離線緩存,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10
Android實(shí)現(xiàn)伸縮彈力分布菜單效果的示例
本文介紹下在Android中實(shí)現(xiàn)伸縮彈力分布菜單效果。這種效果比較炫酷,有需要的朋友可以參考一下。2016-10-10
Flutter 設(shè)置全局字體的實(shí)現(xiàn)
本文主要介紹了Flutter 設(shè)置全局字體的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02

