本篇文章給大家分享的是有關Android開發(fā)中利用ListView實現(xiàn)一個漸變式的下拉刷新動畫,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
創(chuàng)新互聯(lián)建站專注為客戶提供全方位的互聯(lián)網(wǎng)綜合服務,包含不限于網(wǎng)站設計制作、做網(wǎng)站、奉賢網(wǎng)絡推廣、微信小程序定制開發(fā)、奉賢網(wǎng)絡營銷、奉賢企業(yè)策劃、奉賢品牌公關、搜索引擎seo、人物專訪、企業(yè)宣傳片、企業(yè)代運營等,從售前售中售后,我們都將竭誠為您服務,您的肯定,是我們最大的嘉獎;創(chuàng)新互聯(lián)建站為所有大學生創(chuàng)業(yè)者提供奉賢建站搭建服務,24小時服務熱線:18980820575,官方網(wǎng)址:www.cdcxhl.com
主要要點
listview刷新過程中主要有三個步驟當前:狀態(tài)為下拉刷新,當前狀態(tài)為下拉刷新,當前狀態(tài)為放開刷新,當前狀態(tài)為正在刷新;主要思路為三個步驟分別對應三個自定義的view;即ibuRefreshFirstStepView,ibuRefreshSecondStepView,ibuRefreshThirdStepView。
效果圖
ibuRefreshFirstStepView代碼,例如:
private Bitmap initialBitmap; private float mCurrentProgress; private Bitmap scaledBitmap; public ibuRefreshFirstStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } public ibuRefreshFirstStepView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public ibuRefreshFirstStepView(Context context) { super(context); init(context); } private void init(Context context) { //這個就是那個火箭圖片 initialBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian1)); } /** * 重寫onMeasure方法主要是設置wrap_content時 View的大小 * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //根據(jù)設置的寬度來計算高度 設置為符合第二階段娃娃圖片的寬高比例 setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(widthMeasureSpec)*initialBitmap.getHeight()/initialBitmap.getWidth()); } /** * 當wrap_content的時候,寬度即為第二階段娃娃圖片的寬度 * @param widMeasureSpec * @return */ private int measureWidth(int widMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widMeasureSpec); int mode = MeasureSpec.getMode(widMeasureSpec); if (mode == MeasureSpec.EXACTLY){ result = size; }else{ result = initialBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST){ result = Math.min(result,size); } } return result; } /** * 在onLayout里面獲得測量后View的寬高 * @param changed * @param left * @param top * @param right * @param bottom */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); // 給火箭圖片進行等比例的縮放 scaledBitmap = Bitmap.createScaledBitmap(initialBitmap,89,110, false); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //這個方法是對畫布進行縮放,從而達到橢圓形圖片的縮放,第一個參數(shù)為寬度縮放比例,第二個參數(shù)為高度縮放比例, // canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight/2); //將等比例縮放后的橢圓形畫在畫布上面 canvas.drawBitmap(scaledBitmap,90,dip2px(getContext(),80*mCurrentProgress),null); } /** * 根據(jù)手機的分辨率從 dp 的單位 轉(zhuǎn)成為 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } /** * 設置縮放比例,從0到1 0為最小 1為最大 * @param currentProgress */ public void setCurrentProgress(float currentProgress){ mCurrentProgress = currentProgress; } }
ibuRefreshSecondStepView代碼,例如:
private Bitmap endBitmap,scaledBitmap; public ibuRefreshSecondStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ibuRefreshSecondStepView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ibuRefreshSecondStepView(Context context) { super(context); init(); } private void init() { endBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian2), 89, 110, false); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureWidth(widthMeasureSpec) * endBitmap.getHeight() / endBitmap.getWidth()); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); scaledBitmap = Bitmap.createScaledBitmap(endBitmap, 89, 110, false); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(endBitmap, 90, dip2px(getContext(), 80 * 1), null); } /** * 根據(jù)手機的分辨率從 dp 的單位 轉(zhuǎn)成為 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } private int measureWidth(int widthMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; }else { result = endBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } }
ibuRefreshThirdStepView代碼,例如:
private Bitmap endBitmap,scaledBitmap; public ibuRefreshThirdStepView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public ibuRefreshThirdStepView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public ibuRefreshThirdStepView(Context context) { super(context); init(); } private void init() { endBitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian3), 89, 170, false); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(endBitmap, 90, dip2px(getContext(), 40 * 1), null); } /** * 根據(jù)手機的分辨率從 dp 的單位 轉(zhuǎn)成為 px(像素) */ public static int dip2px(Context context, float dpValue) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dpValue * scale + 0.5f); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.getWidth()); } private int measureWidth(int widthMeasureSpec){ int result = 0; int size = MeasureSpec.getSize(widthMeasureSpec); int mode = MeasureSpec.getMode(widthMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; }else { result = endBitmap.getWidth(); if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; }
代碼塊
IbuListView 代碼,例如:
private static final int DONE = 0; private static final int PULL_TO_REFRESH = 1; private static final int RELEASE_TO_REFRESH = 2; private static final int REFRESHING = 3; private static final int RATIO = 3; private RelativeLayout headerView; private int headerViewHeight; private float startY; private float offsetY; private TextView tv_pull_to_refresh; private OnMeiTuanRefreshListener mOnRefreshListener; private int state; private int mFirstVisibleItem; private boolean isRecord; private boolean isEnd; private boolean isRefreable; private FrameLayout mAnimContainer; // private Animation animation; private SimpleDateFormat format; private ibuRefreshFirstStepView mFirstView; private ibuRefreshSecondStepView mSecondView; private AnimationDrawable secondAnim; private ibuRefreshThirdStepView mThirdView; private AnimationDrawable thirdAnim; public IbuListView(Context context) { super(context); init(context); } public IbuListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public IbuListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public interface OnMeiTuanRefreshListener{ void onRefresh(); } /** * 回調(diào)接口,想實現(xiàn)下拉刷新的listview實現(xiàn)此接口 * @param onRefreshListener */ public void setOnMeiTuanRefreshListener(OnMeiTuanRefreshListener onRefreshListener){ mOnRefreshListener = onRefreshListener; isRefreable = true; } /** * 刷新完畢,從主線程發(fā)送過來,并且改變headerView的狀態(tài)和文字動畫信息 */ public void setOnRefreshComplete(){ //一定要將isEnd設置為true,以便于下次的下拉刷新 isEnd = true; state = DONE; changeHeaderByState(state); } private ImageView imageViewBack,imageView_B; private void init(Context context) { setOverScrollMode(View.OVER_SCROLL_NEVER); setOnScrollListener(this); headerView = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.ibu_item, null, false); imageViewBack= (ImageView) headerView.findViewById(R.id.icon_back); imageView_B= (ImageView) headerView.findViewById(R.id.image_b); mFirstView = (ibuRefreshFirstStepView) headerView.findViewById(R.id.first_view); tv_pull_to_refresh = (TextView) headerView.findViewById(R.id.tv_pull_to_refresh); mSecondView = (ibuRefreshSecondStepView) headerView.findViewById(R.id.second_view); mThirdView = (ibuRefreshThirdStepView) headerView.findViewById(R.id.third_view); measureView(headerView); addHeaderView(headerView); headerViewHeight = headerView.getMeasuredHeight(); headerView.setPadding(0, -headerViewHeight, 0, 0); Log.i("zhangqi","headerViewHeight="+headerViewHeight); state = DONE; isEnd = true; isRefreable = false; } @Override public void onScrollStateChanged(AbsListView absListView, int i) { } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { mFirstVisibleItem = firstVisibleItem; } @Override public boolean onTouchEvent(MotionEvent ev) { if (isEnd) {//如果現(xiàn)在時結(jié)束的狀態(tài),即刷新完畢了,可以再次刷新了,在onRefreshComplete中設置 if (isRefreable) {//如果現(xiàn)在是可刷新狀態(tài) 在setOnMeiTuanListener中設置為true switch (ev.getAction()){ //用戶按下 case MotionEvent.ACTION_DOWN: //如果當前是在listview頂部并且沒有記錄y坐標 if (mFirstVisibleItem == 0 && !isRecord) { //將isRecord置為true,說明現(xiàn)在已記錄y坐標 isRecord = true; //將當前y坐標賦值給startY起始y坐標 startY = ev.getY(); } imageView_B.setVisibility(VISIBLE); break; //用戶滑動 case MotionEvent.ACTION_MOVE: //再次得到y(tǒng)坐標,用來和startY相減來計算offsetY位移值 float tempY = ev.getY(); //再起判斷一下是否為listview頂部并且沒有記錄y坐標 if (mFirstVisibleItem == 0 && !isRecord) { isRecord = true; startY = tempY; } //如果當前狀態(tài)不是正在刷新的狀態(tài),并且已經(jīng)記錄了y坐標 if (state!=REFRESHING && isRecord ) { //計算y的偏移量 offsetY = tempY - startY; //計算當前滑動的高度 float currentHeight = (-headerViewHeight+offsetY/3); //用當前滑動的高度和頭部headerView的總高度進行比 計算出當前滑動的百分比 0到1 float currentProgress = 1+currentHeight/headerViewHeight; //如果當前百分比大于1了,將其設置為1,目的是讓第一個狀態(tài)的橢圓不再繼續(xù)變大 if (currentProgress>=1) { currentProgress = 1; } //如果當前的狀態(tài)是放開刷新,并且已經(jīng)記錄y坐標 if (state == RELEASE_TO_REFRESH && isRecord) { setSelection(0); //如果當前滑動的距離小于headerView的總高度 if (-headerViewHeight+offsetY/RATIO<0) { //將狀態(tài)置為下拉刷新狀態(tài) state = PULL_TO_REFRESH; //根據(jù)狀態(tài)改變headerView,主要是更新動畫和文字等信息 changeHeaderByState(state); //如果當前y的位移值小于0,即為headerView隱藏了 }else if (offsetY<=0) { //將狀態(tài)變?yōu)閐one state = DONE; //根據(jù)狀態(tài)改變headerView,主要是更新動畫和文字等信息 changeHeaderByState(state); } } //如果當前狀態(tài)為下拉刷新并且已經(jīng)記錄y坐標 if (state == PULL_TO_REFRESH && isRecord) { setSelection(0); //如果下拉距離大于等于headerView的總高度 if (-headerViewHeight+offsetY/RATIO>=0) { //將狀態(tài)變?yōu)榉砰_刷新 state = RELEASE_TO_REFRESH; //根據(jù)狀態(tài)改變headerView,主要是更新動畫和文字等信息 changeHeaderByState(state); //如果當前y的位移值小于0,即為headerView隱藏了 }else if (offsetY<=0) { //將狀態(tài)變?yōu)閐one state = DONE; //根據(jù)狀態(tài)改變headerView,主要是更新動畫和文字等信息 changeHeaderByState(state); } } //如果當前狀態(tài)為done并且已經(jīng)記錄y坐標 if (state == DONE && isRecord) { //如果位移值大于0 if (offsetY>=0) { //將狀態(tài)改為下拉刷新狀態(tài) state = PULL_TO_REFRESH; } } //如果為下拉刷新狀態(tài) if (state == PULL_TO_REFRESH) { //則改變headerView的padding來實現(xiàn)下拉的效果 headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0,0); //給第一個狀態(tài)的View設置當前進度值 mFirstView.setCurrentProgress(currentProgress); //重畫 mFirstView.postInvalidate(); } //如果為放開刷新狀態(tài) if (state == RELEASE_TO_REFRESH) { //改變headerView的padding值 headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0, 0); //給第一個狀態(tài)的View設置當前進度值 mFirstView.setCurrentProgress(currentProgress); //重畫 mFirstView.postInvalidate(); } } break; //當用戶手指抬起時 case MotionEvent.ACTION_UP: //如果當前狀態(tài)為下拉刷新狀態(tài) if (state == PULL_TO_REFRESH) { //平滑的隱藏headerView this.smoothScrollBy((int)(-headerViewHeight+offsetY/RATIO)+headerViewHeight, 500); //根據(jù)狀態(tài)改變headerView changeHeaderByState(state); } //如果當前狀態(tài)為放開刷新 if (state == RELEASE_TO_REFRESH) { //平滑的滑到正好顯示headerView this.smoothScrollBy((int)(-headerViewHeight+offsetY/RATIO), 500); //將當前狀態(tài)設置為正在刷新 state = REFRESHING; //回調(diào)接口的onRefresh方法 mOnRefreshListener.onRefresh(); //根據(jù)狀態(tài)改變headerView changeHeaderByState(state); } //這一套手勢執(zhí)行完,一定別忘了將記錄y坐標的isRecord改為false,以便于下一次手勢的執(zhí)行 isRecord = false; break; } } } return super.onTouchEvent(ev); } private Animation animation; /** * 根據(jù)狀態(tài)改變headerView的動畫和文字顯示 * @param state */ private void changeHeaderByState(int state){ switch (state) { case DONE://如果的隱藏的狀態(tài) //設置headerView的padding為隱藏 headerView.setPadding(0, -headerViewHeight, 0, 0); //第一狀態(tài)的view顯示出來 mFirstView.setVisibility(View.VISIBLE); imageView_B.setVisibility(VISIBLE); tv_pull_to_refresh.setText("下拉刷新"); //第二狀態(tài)的view隱藏起來 mSecondView.setVisibility(View.GONE); //停止第二狀態(tài)的動畫 secondAnim.stop(); //第三狀態(tài)的view隱藏起來 mThirdView.setVisibility(View.GONE); //停止第三狀態(tài)的動畫 thirdAnim.stop(); break; case RELEASE_TO_REFRESH://當前狀態(tài)為放開刷新 //文字顯示為放開刷新 tv_pull_to_refresh.setText("放開刷新"); //第一狀態(tài)view隱藏起來 mFirstView.setVisibility(View.GONE); //第二狀態(tài)view顯示出來 mSecondView.setVisibility(View.VISIBLE); //播放第二狀態(tài)的動畫 secondAnim.start(); //第三狀態(tài)view隱藏起來 mThirdView.setVisibility(View.GONE); //停止第三狀態(tài)的動畫 thirdAnim.stop(); break; case PULL_TO_REFRESH://當前狀態(tài)為下拉刷新 imageView_B.setVisibility(VISIBLE); //設置文字為下拉刷新 tv_pull_to_refresh.setText("下拉刷新"); //第一狀態(tài)view顯示出來 mFirstView.setVisibility(View.VISIBLE); //第二狀態(tài)view隱藏起來 mSecondView.setVisibility(View.GONE); //第二狀態(tài)動畫停止 secondAnim.stop(); //第三狀態(tài)view隱藏起來 mThirdView.setVisibility(View.GONE); //第三狀態(tài)動畫停止 thirdAnim.stop(); break; case REFRESHING://當前狀態(tài)為正在刷新 //文字設置為正在刷新 tv_pull_to_refresh.setText("正在刷新"); //第一狀態(tài)view隱藏起來 mFirstView.setVisibility(View.GONE); //第三狀態(tài)view顯示出來 mThirdView.setVisibility(View.VISIBLE); //第二狀態(tài)view隱藏起來 mSecondView.setVisibility(View.GONE); //停止第二狀態(tài)動畫 secondAnim.stop(); //啟動第三狀態(tài)view thirdAnim.start(); imageView_B.setVisibility(GONE); animation = new TranslateAnimation(0, 0, 0, 600); animation.setDuration(3000); imageViewBack.setAnimation(animation); break; default: break; } } private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } }
以上就是Android開發(fā)中利用ListView實現(xiàn)一個漸變式的下拉刷新動畫,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學到更多知識。更多詳情敬請關注創(chuàng)新互聯(lián)行業(yè)資訊頻道。