Android簡潔的下拉放大刷新效果示例
序言
國慶放假過后眼看一年又要過完了,年初指望著已經(jīng)有一年的經(jīng)驗(yàn)本以為自己不是剛出校的學(xué)生以為翅膀已經(jīng)硬了,打算辭職換新工作,一面試才發(fā)現(xiàn)自己就是個(gè)垃圾,什么oninterceptEvent,dispatchTouchEvent ,Aysnctask都不會。做了一年的項(xiàng)目也是用的Xutils2.6版本 還有一堆不常用不好的不主流不時(shí)尚的框架,技術(shù)也沒任何長進(jìn)。還好公司真的輕松(所以也學(xué)不到任何東西)可以趁閑下來的時(shí)間多學(xué)點(diǎn)東西。于是寫了個(gè)簡單但也有需求的控件練練手。
首先先看效果圖吧
這個(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)思路
其思路很簡單
1.首先在構(gòu)造方法中動(dòng)態(tài)添加下拉縮放的imageView和刷新的refreshProgress(控件中為實(shí)現(xiàn)跟隨手指滑動(dòng)旋轉(zhuǎn)因此使用的為imageView)
2.獲取到listview對象,然后監(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對象,因?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
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android Map新用法:MapFragment應(yīng)用介紹
MapView ,MapActivity 這種的局限在于,必須要繼承MapActivity,否則無法使用MapView,但是,MapFragment 這種的局限在于,必須要安裝Google Play Service ,也就是說必須是原生rom。而且sdk要在12以上2013-01-01Android編程實(shí)現(xiàn)仿QQ發(fā)表說說,上傳照片及彈出框效果【附demo源碼下載】
這篇文章主要介紹了Android編程實(shí)現(xiàn)仿QQ發(fā)表說說,上傳照片及彈出框效果,涉及Android動(dòng)畫特效的相關(guān)實(shí)現(xiàn)技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-01-01Android自定義viewgroup快速滑動(dòng)(4)
這篇文章主要為大家詳細(xì)介紹了Android自定義viewgroup快速滑動(dòng)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-12-12SimpleCommand框架ImageLoader API詳解(三)
這篇文章主要為大家詳細(xì)介紹了SimpleCommand框架ImageLoader API,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10Android通過ImageView設(shè)置手指滑動(dòng)控件縮放
這篇文章主要介紹了Android通過ImageView設(shè)置手指滑動(dòng)控件縮放效果,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-12-12Android 監(jiān)聽?wèi)?yīng)用前/后臺切換實(shí)例代碼
本篇文章主要介紹了Android 監(jiān)聽?wèi)?yīng)用前/后臺切換實(shí)例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06Android編程開發(fā)實(shí)現(xiàn)帶進(jìn)度條和百分比的多線程下載
這篇文章主要介紹了Android編程開發(fā)實(shí)現(xiàn)帶進(jìn)度條和百分比的多線程下載,總結(jié)了前面關(guān)于Java多線程下載的技巧,實(shí)例分析了Android實(shí)現(xiàn)帶百分比和進(jìn)度條的多線程下載技巧,需要的朋友可以參考下2015-12-12Android 使用Path實(shí)現(xiàn)涂鴉功能
到月底了最近比較空閑,今天抽空給大家實(shí)現(xiàn)一個(gè)涂鴉效果,會分幾步實(shí)現(xiàn),這里有一個(gè)重要的知識點(diǎn)就是圖層,要理解這個(gè)。下面先從簡單的說起,一起看看代碼吧2016-12-12