Android自定义控件——PullZoomView

本文介绍PullZoomView的简单实现,如图:



就是通过下拉ListView或者ScrollView或者更多的View如GridView,RecycleView等等,的时候对Header有一个放大缩小的效果

实现思路就是根据所需要封装的不同的下拉控件来做不同的实现,比如:

ListView:该控件本身有添加Header的功能,我们只需做简单的处理就可以用了,在满足一定条件时做事件拦截,让整个控件向下滚动的时候回传一个value用来改变Header的高度。

ScrollView:这就需要我们自己封装一个Header在ScrollView的孩子控件当中。滚动的时候和ListView做相同的操作即可。



IPullZoom                               定义公共接口

PullZoomBase                         抽象公共的方法

PullZoomListView                  ListView的实现

PullZoomScrollView              ScrollView的实现


IPullZoom.java

  1. public interface IPullZoom {  
  2.   
  3.     void initHeader(TypedArray a);  
  4. }  

PullZoomBase.java

  1. public abstract class PullZoomBase<T extends View> extends LinearLayout implements IPullZoom {  
  2.     /** 
  3.      * 根布局,用来装所有内容 
  4.      */  
  5.     protected T mRootView;  
  6.     /** 
  7.      * 定义的显示伸缩效果的View 
  8.      */  
  9.     protected View mZoomView;  
  10.     /** 
  11.      * 伸缩效果上展示的内容 
  12.      */  
  13.     protected View mHeadView;  
  14.     /** 
  15.      * 是否允许下拉 
  16.      */  
  17.     private boolean isPullEnable = true;  
  18.   
  19.     private boolean isZooming;  
  20.   
  21.     private boolean isHeadHide;  
  22.   
  23.     private boolean isDragging;  
  24.   
  25.     private float mLastX;  
  26.   
  27.     private float mLastY;  
  28.   
  29.     private float mInitX;  
  30.   
  31.     private float mInitY;  
  32.   
  33.     private int mTouchSlop;  
  34.   
  35.     public PullZoomBase(Context context) {  
  36.         this(context, null);  
  37.     }  
  38.   
  39.     public PullZoomBase(Context context, AttributeSet attrs) {  
  40.         this(context, attrs, 0);  
  41.     }  
  42.   
  43.     public PullZoomBase(Context context, AttributeSet attrs, int defStyleAttr) {  
  44.         super(context, attrs, defStyleAttr);  
  45.         ViewConfiguration config = ViewConfiguration.get(context);  
  46.         mTouchSlop = config.getScaledTouchSlop();  
  47.         mRootView = initRootView(context, attrs);  
  48.         LayoutInflater inflater = LayoutInflater.from(context);  
  49.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullZoomView);  
  50.         int zoomResId = a.getResourceId(R.styleable.PullZoomView_zoomview, 0);  
  51.         if (zoomResId > 0) {  
  52.             mZoomView = inflater.inflate(zoomResId, nullfalse);  
  53.         }  
  54.         int headResId = a.getResourceId(R.styleable.PullZoomView_headview, 0);  
  55.         if (headResId > 0) {  
  56.             mHeadView = inflater.inflate(headResId, nullfalse);  
  57.         }  
  58.         initHeader(a);  
  59.         a.recycle();  
  60.         addView(mRootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);  
  61.     }  
  62.   
  63.     @Override  
  64.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  65.         if (!isPullEnable() || isHeadHide()) {  
  66.             return false;  
  67.         }  
  68.         int action = ev.getAction();  
  69.         if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {  
  70.             isDragging = false;  
  71.             return false;  
  72.         }  
  73.         if (action != MotionEvent.ACTION_DOWN && isDragging) {  
  74.             return true;  
  75.         }  
  76.         switch (action) {  
  77.             case MotionEvent.ACTION_DOWN:  
  78.                 if (allowStart()) {  
  79.                     mLastX = mInitX = ev.getX();  
  80.                     mLastY = mInitY = ev.getY();  
  81.                     isDragging = false;  
  82.                 }  
  83.                 break;  
  84.             case MotionEvent.ACTION_MOVE:  
  85.                 if (allowStart()) {  
  86.                     float x = ev.getX();  
  87.                     float y = ev.getY();  
  88.                     float diffX = x - mLastX;  
  89.                     float diffY = y - mLastY;  
  90.                     float diffYAds = Math.abs(diffY);  
  91.                     if (diffYAds > mTouchSlop && diffYAds > Math.abs(diffX)) {  
  92.                         if (diffY >= 1 && allowStart()) {  
  93.                             mLastX = x;  
  94.                             mLastY = y;  
  95.                             isDragging = true;  
  96.                         }  
  97.                     }  
  98.                 }  
  99.                 break;  
  100.         }  
  101.         return isDragging;  
  102.   
  103.     }  
  104.   
  105.     @Override  
  106.     public boolean onTouchEvent(MotionEvent event) {  
  107.         if (!isPullEnable || isHeadHide()) {  
  108.             return false;  
  109.         }  
  110.         if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {  
  111.             return false;  
  112.         }  
  113.         switch (event.getAction()) {  
  114.             case MotionEvent.ACTION_DOWN:  
  115.                 if (allowStart()) {  
  116.                     mLastX = mInitX = event.getX();  
  117.                     mLastY = mInitY = event.getY();  
  118.                     return true;  
  119.                 }  
  120.                 break;  
  121.             case MotionEvent.ACTION_MOVE:  
  122.                 if (allowStart()) {  
  123.                     mLastX = event.getX();  
  124.                     mLastY = event.getY();  
  125.                     final int newScrollValue = Math.round(Math.min(mInitY - mLastY, 0) / 2.0f);  
  126.                     pull(newScrollValue);  
  127.                     return true;  
  128.                 }  
  129.                 break;  
  130.             case MotionEvent.ACTION_UP:  
  131.             case MotionEvent.ACTION_CANCEL:  
  132.                 if (isDragging) {  
  133.                     isDragging = false;  
  134.                     smoothRestore();  
  135.                 }  
  136.                 break;  
  137.         }  
  138.         return false;  
  139.     }  
  140.   
  141.     public boolean isPullEnable() {  
  142.         return isPullEnable;  
  143.     }  
  144.   
  145.     public void setIsPullEnable(boolean isPullEnable) {  
  146.         this.isPullEnable = isPullEnable;  
  147.     }  
  148.   
  149.     public boolean isHeadHide() {  
  150.         return isHeadHide;  
  151.     }  
  152.   
  153.     public void setIsHeadHide(boolean isHeadHide) {  
  154.         this.isHeadHide = isHeadHide;  
  155.     }  
  156.   
  157.   
  158.     /** 
  159.      * 创建根布局,例如ListView,GridView,RecycleView,ScrollView等等 
  160.      * 
  161.      * @param context 
  162.      * @param set 
  163.      * @return 
  164.      */  
  165.     public abstract T initRootView(Context context, AttributeSet set);  
  166.   
  167.     /** 
  168.      * 判定是否允许开始滚动 
  169.      * 
  170.      * @return 
  171.      */  
  172.     public abstract boolean allowStart();  
  173.   
  174.     /** 
  175.      * 传入一个计算值,用来对Header做放大缩小操作 
  176.      * 
  177.      * @param value 
  178.      */  
  179.     public abstract void pull(int value);  
  180.   
  181.     /** 
  182.      * 
  183.      */  
  184.     public abstract void smoothRestore();  
  185.   
  186.   
  187. }  


PullZoomListView.java

  1. public class PullZoomListView extends PullZoomBase<ListView> {  
  2.   
  3.     private FrameLayout mHeaderContainer;  
  4.   
  5.     private int mHeaderHeight;  
  6.   
  7.     private SmoothRestore mSmoothRestore;  
  8.   
  9.     public static Interpolator mInterpolator = new Interpolator() {  
  10.         @Override  
  11.         public float getInterpolation(float input) {  
  12.             float f = input - 1.0F;  
  13.             return 1.0F + f * (f * (f * (f * f)));  
  14.         }  
  15.     };  
  16.   
  17.     public PullZoomListView(Context context) {  
  18.         this(context, null);  
  19.     }  
  20.   
  21.     public PullZoomListView(Context context, AttributeSet attrs) {  
  22.         this(context, attrs, 0);  
  23.     }  
  24.   
  25.     public PullZoomListView(Context context, AttributeSet attrs, int defStyleAttr) {  
  26.         super(context, attrs, defStyleAttr);  
  27.         mSmoothRestore = new SmoothRestore();  
  28.     }  
  29.   
  30.     @Override  
  31.     public ListView initRootView(Context context, AttributeSet set) {  
  32.         ListView listview = new ListView(context, set);  
  33.         return listview;  
  34.     }  
  35.   
  36.     @Override  
  37.     public void initHeader(TypedArray a) {  
  38.         mHeaderContainer = new FrameLayout(getContext());  
  39.         if (mZoomView != null) {  
  40.             mHeaderContainer.addView(mZoomView);  
  41.         }  
  42.         if (mHeadView != null) {  
  43.             mHeaderContainer.addView(mHeadView);  
  44.         }  
  45.         mRootView.addHeaderView(mHeaderContainer);  
  46.     }  
  47.   
  48.     public void setAdapter(BaseAdapter adapter) {  
  49.         mRootView.setAdapter(adapter);  
  50.     }  
  51.   
  52.     public void setHeaderLayoutParams(AbsListView.LayoutParams params) {  
  53.         if (mHeaderContainer != null) {  
  54.             mHeaderContainer.setLayoutParams(params);  
  55.             mHeaderHeight = params.height;  
  56.         }  
  57.     }  
  58.   
  59.     public void updateHeader() {  
  60.         if (mHeaderContainer != null) {  
  61.             mRootView.removeHeaderView(mHeaderContainer);  
  62.             mHeaderContainer.removeAllViews();  
  63.             if (mZoomView != null) {  
  64.                 mHeaderContainer.addView(mZoomView);  
  65.             }  
  66.             if (mHeadView != null) {  
  67.                 mHeaderContainer.addView(mHeadView);  
  68.             }  
  69.             mHeaderHeight = mHeaderContainer.getHeight();  
  70.             mRootView.addHeaderView(mHeaderContainer);  
  71.         }  
  72.     }  
  73.   
  74.     @Override  
  75.     public boolean allowStart() {  
  76.         return isFirstItemVisiable();  
  77.     }  
  78.   
  79.     private boolean isFirstItemVisiable() {  
  80.         Adapter adapter = mRootView.getAdapter();  
  81.         if (null == adapter || adapter.isEmpty()) {  
  82.             return true;  
  83.         } else {  
  84.             if (mRootView.getFirstVisiblePosition() <= 1) {  
  85.                 View view = mRootView.getChildAt(0);  
  86.                 if (view != null) {  
  87.                     return view.getTop() >= mRootView.getTop();  
  88.                 }  
  89.             }  
  90.         }  
  91.         return false;  
  92.     }  
  93.   
  94.     @Override  
  95.     public void pull(int value) {  
  96.         if (mSmoothRestore != null && !mSmoothRestore.isFinish()) {  
  97.             mSmoothRestore.abort();  
  98.         }  
  99.         ViewGroup.LayoutParams params = mHeaderContainer.getLayoutParams();  
  100.         params.height = Math.abs(value) + mHeaderHeight;  
  101.         mHeaderContainer.setLayoutParams(params);  
  102.     }  
  103.   
  104.     @Override  
  105.     public void smoothRestore() {  
  106.         mSmoothRestore.start(200L);  
  107.     }  
  108.   
  109.     class SmoothRestore implements Runnable {  
  110.         protected long duration;  
  111.         protected boolean isFinished;  
  112.         protected float scale;  
  113.         protected long starttime;  
  114.   
  115.         SmoothRestore() {  
  116.         }  
  117.   
  118.         public void abort() {  
  119.             isFinished = true;  
  120.         }  
  121.   
  122.         public boolean isFinish() {  
  123.             return isFinished;  
  124.         }  
  125.   
  126.         public void start(long d) {  
  127.             if (mZoomView != null) {  
  128.                 starttime = SystemClock.currentThreadTimeMillis();  
  129.                 duration = d;  
  130.                 scale = (float) mHeaderContainer.getBottom() / mHeaderHeight;  
  131.                 isFinished = false;  
  132.                 post(this);  
  133.             }  
  134.         }  
  135.   
  136.         @Override  
  137.         public void run() {  
  138.             if (mZoomView != null) {  
  139.                 float f2;  
  140.                 ViewGroup.LayoutParams params;  
  141.   
  142.                 if (!isFinished && scale > 1.0D) {  
  143.                     float f1 = ((float) SystemClock.currentThreadTimeMillis() - (float) starttime) / (float) duration;  
  144.                     f2 = scale - (scale - 1.0F) * PullZoomListView.mInterpolator.getInterpolation(f1);  
  145.                     params = mHeaderContainer.getLayoutParams();  
  146.                     if (f2 > 1.0F) {  
  147.                         params.height = (int) (f2 * mHeaderHeight);  
  148.                         mHeaderContainer.setLayoutParams(params);  
  149.                         post(this);  
  150.                         return;  
  151.                     }  
  152.                     isFinished = true;  
  153.                 }  
  154.   
  155.             }  
  156.         }  
  157.     }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值