溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Android開發(fā)中利用ListView實(shí)現(xiàn)一個(gè)漸變式的下拉刷新動(dòng)畫

發(fā)布時(shí)間:2020-11-23 16:50:31 來源:億速云 閱讀:217 作者:Leah 欄目:移動(dòng)開發(fā)

本篇文章給大家分享的是有關(guān)Android開發(fā)中利用ListView實(shí)現(xiàn)一個(gè)漸變式的下拉刷新動(dòng)畫,小編覺得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

主要要點(diǎn)

listview刷新過程中主要有三個(gè)步驟當(dāng)前:狀態(tài)為下拉刷新,當(dāng)前狀態(tài)為下拉刷新,當(dāng)前狀態(tài)為放開刷新,當(dāng)前狀態(tài)為正在刷新;主要思路為三個(gè)步驟分別對(duì)應(yīng)三個(gè)自定義的view;即ibuRefreshFirstStepView,ibuRefreshSecondStepView,ibuRefreshThirdStepView。

效果圖

Android開發(fā)中利用ListView實(shí)現(xiàn)一個(gè)漸變式的下拉刷新動(dòng)畫

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) {
  //這個(gè)就是那個(gè)火箭圖片
  initialBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.img_huojian1));

 }

 /**
  * 重寫onMeasure方法主要是設(shè)置wrap_content時(shí) View的大小
  * @param widthMeasureSpec
  * @param heightMeasureSpec
  */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  //根據(jù)設(shè)置的寬度來計(jì)算高度 設(shè)置為符合第二階段娃娃圖片的寬高比例
  setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(widthMeasureSpec)*initialBitmap.getHeight()/initialBitmap.getWidth());
 }

 /**
  * 當(dāng)wrap_content的時(shí)候,寬度即為第二階段娃娃圖片的寬度
  * @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里面獲得測(cè)量后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);

  // 給火箭圖片進(jìn)行等比例的縮放
  scaledBitmap = Bitmap.createScaledBitmap(initialBitmap,89,110, false);
 }


 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  //這個(gè)方法是對(duì)畫布進(jìn)行縮放,從而達(dá)到橢圓形圖片的縮放,第一個(gè)參數(shù)為寬度縮放比例,第二個(gè)參數(shù)為高度縮放比例,
//  canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/2, measuredHeight/2);
  //將等比例縮放后的橢圓形畫在畫布上面
  canvas.drawBitmap(scaledBitmap,90,dip2px(getContext(),80*mCurrentProgress),null);

 }
 /**
  * 根據(jù)手機(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);
 }
 /**
  * 設(shè)置縮放比例,從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ù)手機(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ù)手機(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)接口,想實(shí)現(xiàn)下拉刷新的listview實(shí)現(xiàn)此接口
  * @param onRefreshListener
  */
 public void setOnMeiTuanRefreshListener(OnMeiTuanRefreshListener onRefreshListener){
  mOnRefreshListener = onRefreshListener;
  isRefreable = true;
 }

 /**
  * 刷新完畢,從主線程發(fā)送過來,并且改變headerView的狀態(tài)和文字動(dòng)畫信息
  */
 public void setOnRefreshComplete(){
  //一定要將isEnd設(shè)置為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)在時(shí)結(jié)束的狀態(tài),即刷新完畢了,可以再次刷新了,在onRefreshComplete中設(shè)置
   if (isRefreable) {//如果現(xiàn)在是可刷新狀態(tài) 在setOnMeiTuanListener中設(shè)置為true
    switch (ev.getAction()){
     //用戶按下
    case MotionEvent.ACTION_DOWN:
     //如果當(dāng)前是在listview頂部并且沒有記錄y坐標(biāo)
     if (mFirstVisibleItem == 0 && !isRecord) {
      //將isRecord置為true,說明現(xiàn)在已記錄y坐標(biāo)
      isRecord = true;
      //將當(dāng)前y坐標(biāo)賦值給startY起始y坐標(biāo)
      startY = ev.getY();
     }
     imageView_B.setVisibility(VISIBLE);
     break;
    //用戶滑動(dòng)
    case MotionEvent.ACTION_MOVE:
     //再次得到y(tǒng)坐標(biāo),用來和startY相減來計(jì)算offsetY位移值
     float tempY = ev.getY();
     //再起判斷一下是否為listview頂部并且沒有記錄y坐標(biāo)
     if (mFirstVisibleItem == 0 && !isRecord) {
      isRecord = true;
      startY = tempY;
     }
     //如果當(dāng)前狀態(tài)不是正在刷新的狀態(tài),并且已經(jīng)記錄了y坐標(biāo)
     if (state!=REFRESHING && isRecord ) {
      //計(jì)算y的偏移量
      offsetY = tempY - startY;
      //計(jì)算當(dāng)前滑動(dòng)的高度
      float currentHeight = (-headerViewHeight+offsetY/3);
      //用當(dāng)前滑動(dòng)的高度和頭部headerView的總高度進(jìn)行比 計(jì)算出當(dāng)前滑動(dòng)的百分比 0到1
      float currentProgress = 1+currentHeight/headerViewHeight;
      //如果當(dāng)前百分比大于1了,將其設(shè)置為1,目的是讓第一個(gè)狀態(tài)的橢圓不再繼續(xù)變大
      if (currentProgress>=1) {
       currentProgress = 1;
      }
      //如果當(dāng)前的狀態(tài)是放開刷新,并且已經(jīng)記錄y坐標(biāo)
      if (state == RELEASE_TO_REFRESH && isRecord) {
       setSelection(0);
       //如果當(dāng)前滑動(dòng)的距離小于headerView的總高度
       if (-headerViewHeight+offsetY/RATIO<0) {
        //將狀態(tài)置為下拉刷新狀態(tài)
        state = PULL_TO_REFRESH;
        //根據(jù)狀態(tài)改變headerView,主要是更新動(dòng)畫和文字等信息
        changeHeaderByState(state);
        //如果當(dāng)前y的位移值小于0,即為headerView隱藏了
       }else if (offsetY<=0) {
        //將狀態(tài)變?yōu)閐one
        state = DONE;
        //根據(jù)狀態(tài)改變headerView,主要是更新動(dòng)畫和文字等信息
        changeHeaderByState(state);
       }
      }
      //如果當(dāng)前狀態(tài)為下拉刷新并且已經(jīng)記錄y坐標(biāo)
      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,主要是更新動(dòng)畫和文字等信息
        changeHeaderByState(state);
        //如果當(dāng)前y的位移值小于0,即為headerView隱藏了
       }else if (offsetY<=0) {
        //將狀態(tài)變?yōu)閐one
        state = DONE;
        //根據(jù)狀態(tài)改變headerView,主要是更新動(dòng)畫和文字等信息
        changeHeaderByState(state);
       }
      }
      //如果當(dāng)前狀態(tài)為done并且已經(jīng)記錄y坐標(biāo)
      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來實(shí)現(xiàn)下拉的效果
       headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0,0);
       //給第一個(gè)狀態(tài)的View設(shè)置當(dāng)前進(jìn)度值
       mFirstView.setCurrentProgress(currentProgress);
       //重畫
       mFirstView.postInvalidate();
      }
      //如果為放開刷新狀態(tài)
      if (state == RELEASE_TO_REFRESH) {
       //改變headerView的padding值
       headerView.setPadding(0,(int)(-headerViewHeight+offsetY/RATIO) ,0, 0);
       //給第一個(gè)狀態(tài)的View設(shè)置當(dāng)前進(jìn)度值
       mFirstView.setCurrentProgress(currentProgress);
       //重畫
       mFirstView.postInvalidate();
      }
     }
     break;
    //當(dāng)用戶手指抬起時(shí)
    case MotionEvent.ACTION_UP:
     //如果當(dāng)前狀態(tài)為下拉刷新狀態(tài)
     if (state == PULL_TO_REFRESH) {
      //平滑的隱藏headerView
      this.smoothScrollBy((int)(-headerViewHeight+offsetY/RATIO)+headerViewHeight, 500);
      //根據(jù)狀態(tài)改變headerView
      changeHeaderByState(state);
     }
     //如果當(dāng)前狀態(tài)為放開刷新
     if (state == RELEASE_TO_REFRESH) {
      //平滑的滑到正好顯示headerView
      this.smoothScrollBy((int)(-headerViewHeight+offsetY/RATIO), 500);
      //將當(dāng)前狀態(tài)設(shè)置為正在刷新
      state = REFRESHING;
      //回調(diào)接口的onRefresh方法
      mOnRefreshListener.onRefresh();
      //根據(jù)狀態(tài)改變headerView
      changeHeaderByState(state);
     }
     //這一套手勢(shì)執(zhí)行完,一定別忘了將記錄y坐標(biāo)的isRecord改為false,以便于下一次手勢(shì)的執(zhí)行
     isRecord = false;
     break;
    }

   }
  }
  return super.onTouchEvent(ev);
 }

 private Animation animation;
 /**
  * 根據(jù)狀態(tài)改變headerView的動(dòng)畫和文字顯示
  * @param state
  */
 private void changeHeaderByState(int state){
  switch (state) {
  case DONE://如果的隱藏的狀態(tài)
   //設(shè)置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)的動(dòng)畫
   secondAnim.stop();
   //第三狀態(tài)的view隱藏起來
   mThirdView.setVisibility(View.GONE);
   //停止第三狀態(tài)的動(dòng)畫
   thirdAnim.stop();
   break;
  case RELEASE_TO_REFRESH://當(dāng)前狀態(tài)為放開刷新
   //文字顯示為放開刷新
   tv_pull_to_refresh.setText("放開刷新");
   //第一狀態(tài)view隱藏起來
   mFirstView.setVisibility(View.GONE);
   //第二狀態(tài)view顯示出來
   mSecondView.setVisibility(View.VISIBLE);
   //播放第二狀態(tài)的動(dòng)畫
  secondAnim.start();
   //第三狀態(tài)view隱藏起來
   mThirdView.setVisibility(View.GONE);
   //停止第三狀態(tài)的動(dòng)畫
  thirdAnim.stop();
   break;
  case PULL_TO_REFRESH://當(dāng)前狀態(tài)為下拉刷新
   imageView_B.setVisibility(VISIBLE);
   //設(shè)置文字為下拉刷新
   tv_pull_to_refresh.setText("下拉刷新");
   //第一狀態(tài)view顯示出來
   mFirstView.setVisibility(View.VISIBLE);
   //第二狀態(tài)view隱藏起來
   mSecondView.setVisibility(View.GONE);
   //第二狀態(tài)動(dòng)畫停止
   secondAnim.stop();
   //第三狀態(tài)view隱藏起來
   mThirdView.setVisibility(View.GONE);
   //第三狀態(tài)動(dòng)畫停止
   thirdAnim.stop();
   break;
  case REFRESHING://當(dāng)前狀態(tài)為正在刷新
   //文字設(shè)置為正在刷新
   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)動(dòng)畫
   secondAnim.stop();
   //啟動(dòng)第三狀態(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實(shí)現(xiàn)一個(gè)漸變式的下拉刷新動(dòng)畫,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見到或用到的。希望你能通過這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI