Android簡(jiǎn)潔的下拉放大刷新效果示例
序言
國(guó)慶放假過后眼看一年又要過完了,年初指望著已經(jīng)有一年的經(jīng)驗(yàn)本以為自己不是剛出校的學(xué)生以為翅膀已經(jīng)硬了,打算辭職換新工作,一面試才發(fā)現(xiàn)自己就是個(gè)垃圾,什么oninterceptEvent,dispatchTouchEvent ,Aysnctask都不會(huì)。做了一年的項(xiàng)目也是用的Xutils2.6版本 還有一堆不常用不好的不主流不時(shí)尚的框架,技術(shù)也沒任何長(zhǎng)進(jìn)。還好公司真的輕松(所以也學(xué)不到任何東西)可以趁閑下來的時(shí)間多學(xué)點(diǎn)東西。于是寫了個(gè)簡(jiǎn)單但也有需求的控件練練手。
首先先看效果圖吧
這個(gè)是listview的效果還有一個(gè)ScrollView的效果當(dāng)然使用和實(shí)現(xiàn)時(shí)一樣的原理這里就一listview來講解,文末傳送門可以看到全部的代碼

1、具體使用
項(xiàng)目build.gradle
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
}
app model build.gradle
compile 'com.github.xypmhxy:PullZoomLayout:1.1'
布局文件中
<com.ren.pullzoom.widget.PullZoomLayout android:id="@+id/pull" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:image_height="200dp" 圖片高度 app:image_res="@mipmap/timg" 圖片資源 app:refresh_enable="true" 是否開啟刷新 app:scale_type="center_crop">//圖片縮放方式 <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/white" /> </com.ren.pullzoom.widget.PullZoomLayout>
2、實(shí)現(xiàn)思路
其思路很簡(jiǎn)單
1.首先在構(gòu)造方法中動(dòng)態(tài)添加下拉縮放的imageView和刷新的refreshProgress(控件中為實(shí)現(xiàn)跟隨手指滑動(dòng)旋轉(zhuǎn)因此使用的為imageView)
2.獲取到listview對(duì)象,然后監(jiān)聽listview的滑動(dòng)事件,判斷滑到頂部后繼續(xù)向下滑動(dòng)的時(shí)候?qū)⑿枰糯蟮腎mageView高度增加然后利用ImageView的Scale方法完成縮放。
3.最后放開手指的時(shí)候用屬性動(dòng)畫讓imageView平滑回到最初狀態(tài),并且如果開啟下拉刷新則回調(diào)其方法。
3、具體實(shí)現(xiàn)
1.動(dòng)態(tài)添加兩個(gè)ImageView(下拉放大的和刷新的progress),大致原理就是將這兩個(gè)ImageView添加到RelativeLayout中然后將RelativeLayout 添加到自身中。代碼如下
/*實(shí)例化頭部布局包含pullZoomImage 和 refreshProgress*/
protected void init(Context context) {
RelativeLayout head = new RelativeLayout(context);
ViewGroup.LayoutParams headParams = new ViewGroup.LayoutParams(-1, -2);
head.setLayoutParams(headParams);
/*實(shí)例化pullZoomImage*/
·······
pullZoomImage.setImageResource(imageRes);
originalParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, imageHeight);
pullZoomImage.setLayoutParams(originalParams);
head.addView(pullZoomImage);
/*實(shí)例化refreshProgress*/
refreshProgress = new ImageView(context);
refreshProgress.setVisibility(GONE);
refreshProgress.setImageResource(R.drawable.refresh);
RelativeLayout.LayoutParams refreshParams = new RelativeLayout.LayoutParams(dip2px(context, 35), dip2px(context, 35));
refreshParams.addRule(RelativeLayout.ALIGN_PARENT_END, RelativeLayout.TRUE);
refreshProgress.setLayoutParams(refreshParams);
head.addView(refreshProgress);
/*將頭部添加到此控件中*/
addView(head, 0);
}
2.是獲取listview對(duì)象,因?yàn)閘istview屬于子控件所以不能在構(gòu)造方法里直接獲取,因?yàn)榇藭r(shí)控件不一定加載完成所以需要等待子控件加載完成后獲取因此在onFinishInflate方法中獲取
@Override
protected void onFinishInflate() {
super.onFinishInflate();
/*獲取listview*/
if (getChildAt(1) instanceof ListView) {
listView = (ListView) getChildAt(1);
listView.setOnScrollListener(scrollListener);
listView.setOnTouchListener(touchListener);
}
}
3.添加listview滑動(dòng)監(jiān)聽判斷是否滑動(dòng)到頂部,可以開啟下拉放大功能
/*listview滑動(dòng)監(jiān)聽*/
protected AbsListView.OnScrollListener scrollListener = new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
/*判斷是否滑動(dòng)到頂部*/
int firstVisibleItem = listView.getFirstVisiblePosition();
if (firstVisibleItem == 0 && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
View firstView = getChildAt(0);
canZoom = firstView != null && firstView.getTop() == 0;
} else
canZoom = false;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
};
4.實(shí)現(xiàn)OnTouchListener根據(jù)事件調(diào)用放大和縮小動(dòng)畫,抬手時(shí)實(shí)現(xiàn)刷新等操作
/*listview touchListener監(jiān)聽*/
protected OnTouchListener touchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent ev) {
if (pullZoomImage == null) return false;
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
pressY = ev.getY();//獲取按下的Y坐標(biāo)
break;
case MotionEvent.ACTION_MOVE:
if (canZoom)//如果已經(jīng)滑動(dòng)到頂部并繼續(xù)滑動(dòng)則開始放大pullZoomImage
return zoomView(ev);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (canZoom)
restroe();//還原pullZoomImage動(dòng)畫
if (needRefresh && refreshListener != null) {//達(dá)到刷新條件并且實(shí)現(xiàn)刷新監(jiān)聽
refreshListener.onRefresh();
rotationProgress();//刷新時(shí)progress旋轉(zhuǎn)動(dòng)畫
} else
refreshProgress.setVisibility(GONE);
//重置變量
needRefresh = false;
canZoom = false;
break;
}
return false;
}
};
縮放imageview
/*放大pullZoomImage*/
protected boolean zoomView(MotionEvent ev) {
float offY = ev.getY() - pressY;
if (offY <= 0 || offY < 16)//滑動(dòng)方向上滑或者滑動(dòng)距離小于16則不管
return false;
/*如果開啟下拉刷新判斷滑動(dòng)距離是否大于refrshSlop則顯示refreshProgress*/
if (refreshEnable) {
needRefresh = offY >= refrshSlop;
if (needRefresh)
refreshProgress.setVisibility(VISIBLE);
}
ViewGroup.LayoutParams params = pullZoomImage.getLayoutParams();
float height = originalParams.height + offY / damp;//根據(jù)滑動(dòng)距離增加pullZoomImage的高度
params.height = (int) height;
scaleImage(height);//放大圖片
rotationProgress(offY);//旋轉(zhuǎn)refreshProgress
if (params.height >= originalParams.height)
pullZoomImage.setLayoutParams(params);//為pullZoomImage設(shè)置改變后的params
return true;
}
/*縮放imageview*/
protected void scaleImage(float height) {
// if (pullZoomImage.getScaleType() == ImageView.ScaleType.CENTER_CROP)
// return;
float scale = (height - originalParams.height) / originalParams.height;//根據(jù)滑動(dòng)的大小判斷縮放比例
pullZoomImage.setScaleX(1 + scale);
pullZoomImage.setScaleY(1 + scale);
}
抬手后通過屬性動(dòng)畫還原pullZoomImage
/*放開后還原pullZoomImage*/
protected void restroe() {
ValueAnimator animator = ValueAnimator.ofFloat(pullZoomImage.getLayoutParams().height, originalParams.height);// 動(dòng)畫更新的監(jiān)聽
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
float height = (float) arg0.getAnimatedValue();// 獲取動(dòng)畫當(dāng)前變化的值
// 根據(jù)最新高度,更新布局高度
ViewGroup.LayoutParams params = pullZoomImage.getLayoutParams();
params.height = (int) height;
scaleImage(height);
pullZoomImage.setLayoutParams(params);
}
});
animator.setDuration(200);// 動(dòng)畫時(shí)間
animator.start();// 開啟動(dòng)畫
}
大致原理就是這樣最后傳送門開啟 PullZoomLayout
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)觸摸移動(dòng)的懸浮窗口功能
這篇文章主要介紹了Android實(shí)現(xiàn)觸摸移動(dòng)的懸浮窗口功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
android自定義滾動(dòng)上下回彈scollView
這篇文章主要為大家詳細(xì)介紹了android自定義滾動(dòng)上下回彈scollView,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
解析Android開發(fā)優(yōu)化之:對(duì)界面UI的優(yōu)化詳解(一)
在Android應(yīng)用開發(fā)過程中,屏幕上控件的布局代碼和程序的邏輯代碼通常是分開的。界面的布局代碼是放在一個(gè)獨(dú)立的xml文件中的,這個(gè)文件里面是樹型組織的,控制著頁面的布局2013-05-05
Android封裝MVP實(shí)現(xiàn)登錄注冊(cè)功能
這篇文章主要為大家詳細(xì)介紹了Android封裝MVP實(shí)現(xiàn)登錄注冊(cè)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-11-11
Android 滑動(dòng)監(jiān)聽RecyclerView線性流+左右劃刪除+上下移動(dòng)
這篇文章主要介紹了Android 滑動(dòng)監(jiān)聽RecyclerView線性流+左右劃刪除+上下移動(dòng)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09
unity3d發(fā)布apk在android虛擬機(jī)中運(yùn)行的詳細(xì)步驟(unity3d導(dǎo)出android apk)
這篇文章主要介紹了unity3d發(fā)布apk在android虛擬機(jī)中運(yùn)行的詳細(xì)步驟,需要的朋友可以參考下2014-05-05
zxing二維碼位矩陣轉(zhuǎn)換成Bitmap位圖的實(shí)戰(zhàn)教程
二維碼的應(yīng)用已經(jīng)可以說是非常廣泛了,下面這篇文章主要給大家介紹了關(guān)于zxing二維碼位矩陣轉(zhuǎn)換成Bitmap位圖的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-09-09
微信公眾平臺(tái)開發(fā)入門教程(SAE方倍工作室)
在這篇微信公眾平臺(tái)開發(fā)教程中,我們假定你已經(jīng)有了PHP語言程序、MySQL數(shù)據(jù)庫(kù)、計(jì)算機(jī)網(wǎng)絡(luò)通訊、及HTTP/XML/CSS/JS等基礎(chǔ)2014-05-05

