欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

android ScrollView實(shí)現(xiàn)下拉放大頭部圖片

 更新時(shí)間:2017年12月22日 16:07:13   作者:Jimi_Wu  
這篇文章主要為大家詳細(xì)介紹了android ScrollView實(shí)現(xiàn)下拉放大頭部圖片,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

之前做項(xiàng)目的時(shí)候,需要實(shí)現(xiàn)類似微博個(gè)人主頁的ScrollView效果,就是到頂部時(shí)繼續(xù)下拉會(huì)放大頂部的圖片。然后在網(wǎng)上找了一篇相關(guān)的實(shí)現(xiàn),效果非常好,代碼也很簡(jiǎn)潔易懂。(傳送門: 自定義scrollView實(shí)現(xiàn)頂部圖片下拉放大),那么我這里就只是在其基礎(chǔ)上修改了一點(diǎn)點(diǎn)而已,比如在代碼中控制圖片居中、增加動(dòng)態(tài)設(shè)置放大的控件、使用自定義的最大放大倍數(shù)等,都是很簡(jiǎn)單的修改,還添加了滑動(dòng)的監(jiān)聽回調(diào)(項(xiàng)目需要)。

效果如下:

思路

老樣子,我們先來說下思路,比起代碼,思路才是最重要的。具體步驟如下:
1. 獲得要放大的控件,并獲得其寬高;
2. 在頂部時(shí)繼續(xù)往下拉,通過LayoutParams改變控件的寬高;
3. 手指抬起時(shí)初始化各項(xiàng)參數(shù),通過屬性動(dòng)畫回彈控件。

實(shí)現(xiàn)

直接看代碼

public class HeadZoomScrollView extends ScrollView {

 public HeadZoomScrollView(Context context) {
  super(context);
 }

 public HeadZoomScrollView(Context context, AttributeSet attrs) {
  super(context, attrs);
 }

 public HeadZoomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
 }

 // 用于記錄下拉位置
 private float y = 0f;
 // zoomView原本的寬高
 private int zoomViewWidth = 0;
 private int zoomViewHeight = 0;

 // 是否正在放大
 private boolean mScaling = false;

 // 放大的view,默認(rèn)為第一個(gè)子view
 private View zoomView;
 public void setZoomView(View zoomView) {
  this.zoomView = zoomView;
 }

 // 滑動(dòng)放大系數(shù),系數(shù)越大,滑動(dòng)時(shí)放大程度越大
 private float mScaleRatio = 0.4f;
 public void setmScaleRatio(float mScaleRatio) {
  this.mScaleRatio = mScaleRatio;
 }

 // 最大的放大倍數(shù)
 private float mScaleTimes = 2f;
 public void setmScaleTimes(int mScaleTimes) {
  this.mScaleTimes = mScaleTimes;
 }

 // 回彈時(shí)間系數(shù),系數(shù)越小,回彈越快
 private float mReplyRatio = 0.5f;
 public void setmReplyRatio(float mReplyRatio) {
  this.mReplyRatio = mReplyRatio;
 }

 @Override
 protected void onFinishInflate() {
  super.onFinishInflate();
//  不可過度滾動(dòng),否則上移后下拉會(huì)出現(xiàn)部分空白的情況
  setOverScrollMode(OVER_SCROLL_NEVER);
//  獲得默認(rèn)第一個(gè)view
  if (getChildAt(0) != null && getChildAt(0) instanceof ViewGroup && zoomView == null) {
   ViewGroup vg = (ViewGroup) getChildAt(0);
   if (vg.getChildCount() > 0) {
    zoomView = vg.getChildAt(0);
   }
  }
 }

 @Override
 public boolean onTouchEvent(MotionEvent ev) {
  if (zoomViewWidth <= 0 || zoomViewHeight <=0) {
   zoomViewWidth = zoomView.getMeasuredWidth();
   zoomViewHeight = zoomView.getMeasuredHeight();
  }
  if (zoomView == null || zoomViewWidth <= 0 || zoomViewHeight <= 0) {
   return super.onTouchEvent(ev);
  }
  switch (ev.getAction()) {
   case MotionEvent.ACTION_MOVE:
    if (!mScaling) {
     if (getScrollY() == 0) {
      y = ev.getY();//滑動(dòng)到頂部時(shí),記錄位置
     } else {
      break;
     }
    }
    int distance = (int) ((ev.getY() - y)*mScaleRatio);
    if (distance < 0) break;//若往下滑動(dòng)
    mScaling = true;
    setZoom(distance);
    return true;
   case MotionEvent.ACTION_UP:
    mScaling = false;
    replyView();
    break;
  }
  return super.onTouchEvent(ev);
 }

 /**放大view*/
 private void setZoom(float s) {
  float scaleTimes = (float) ((zoomViewWidth+s)/(zoomViewWidth*1.0));
//  如超過最大放大倍數(shù),直接返回
  if (scaleTimes > mScaleTimes) return;

  ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
  layoutParams.width = (int) (zoomViewWidth + s);
  layoutParams.height = (int)(zoomViewHeight*((zoomViewWidth+s)/zoomViewWidth));
//  設(shè)置控件水平居中
  ((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - zoomViewWidth) / 2, 0, 0, 0);
  zoomView.setLayoutParams(layoutParams);
 }

 /**回彈*/
 private void replyView() {
  final float distance = zoomView.getMeasuredWidth() - zoomViewWidth;
  // 設(shè)置動(dòng)畫
  ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio));
  anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
   @Override
   public void onAnimationUpdate(ValueAnimator animation) {
    setZoom((Float) animation.getAnimatedValue());
   }
  });
  anim.start();
 }

 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
  super.onScrollChanged(l, t, oldl, oldt);
  if (onScrollListener!=null) onScrollListener.onScroll(l,t,oldl,oldt);
 }

 private OnScrollListener onScrollListener;
 public void setOnScrollListener(OnScrollListener onScrollListener) {
  this.onScrollListener = onScrollListener;
 }

 /**滑動(dòng)監(jiān)聽*/
 public interface OnScrollListener{
  void onScroll(int scrollX,int scrollY,int oldScrollX, int oldScrollY);
 }


}

可以看到,在onTouchEvent方法中,先判斷當(dāng)前是否為放大狀態(tài),不是的話就在頂部的時(shí)候記錄觸摸事件的位置,當(dāng)然這個(gè)寫在ACTION_DOWN事件中也是可以的,若不在頂部,則不處理。

之后計(jì)算滑動(dòng)的距離,若是往下滑動(dòng),則不處理,需要注意的是這個(gè)距離是指當(dāng)前位置與最開始的ACTION_DOWN動(dòng)作的距離,因此當(dāng)這個(gè)距離小于0的時(shí)候,便是”沒放大&&往下滑”,這個(gè)時(shí)候應(yīng)該滑動(dòng)的是ScrollView,恩,沒毛病。當(dāng)距離不小于0的時(shí)候,開始放大控件,可以看到調(diào)用了setZoom方法,注意,在這里其實(shí)控件的下拉放大、上拉恢復(fù)都做了, 回彈其實(shí)也是調(diào)用這個(gè)方法。

抬手的時(shí)候回彈,這個(gè)不需要說了。

代碼整體來說比較簡(jiǎn)單,要是你需要其他實(shí)現(xiàn),也可以很方便地加上,比如我們要放大圖片的時(shí)候像微博一樣,旋轉(zhuǎn)外部的菊花,放手的時(shí)候刷新數(shù)據(jù)怎么辦?你完全可以在
onTouchEvent中增加回調(diào)接口,然后在外部實(shí)現(xiàn)具體邏輯就可以了。

使用

直接像普通的ScollView樣使用就可以了,這個(gè)就不累贅了。

源碼:下載地址

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論