本文介绍PullZoomView的简单实现,如图:
就是通过下拉ListView或者ScrollView或者更多的View如GridView,RecycleView等等,的时候对Header有一个放大缩小的效果
实现思路就是根据所需要封装的不同的下拉控件来做不同的实现,比如:
ListView:该控件本身有添加Header的功能,我们只需做简单的处理就可以用了,在满足一定条件时做事件拦截,让整个控件向下滚动的时候回传一个value用来改变Header的高度。
ScrollView:这就需要我们自己封装一个Header在ScrollView的孩子控件当中。滚动的时候和ListView做相同的操作即可。
IPullZoom 定义公共接口
PullZoomBase 抽象公共的方法
PullZoomListView ListView的实现
PullZoomScrollView ScrollView的实现
IPullZoom.java
- public interface IPullZoom {
- void initHeader(TypedArray a);
- }
PullZoomBase.java
- public abstract class PullZoomBase<T extends View> extends LinearLayout implements IPullZoom {
- /**
- * 根布局,用来装所有内容
- */
- protected T mRootView;
- /**
- * 定义的显示伸缩效果的View
- */
- protected View mZoomView;
- /**
- * 伸缩效果上展示的内容
- */
- protected View mHeadView;
- /**
- * 是否允许下拉
- */
- private boolean isPullEnable = true;
- private boolean isZooming;
- private boolean isHeadHide;
- private boolean isDragging;
- private float mLastX;
- private float mLastY;
- private float mInitX;
- private float mInitY;
- private int mTouchSlop;
- public PullZoomBase(Context context) {
- this(context, null);
- }
- public PullZoomBase(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public PullZoomBase(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- ViewConfiguration config = ViewConfiguration.get(context);
- mTouchSlop = config.getScaledTouchSlop();
- mRootView = initRootView(context, attrs);
- LayoutInflater inflater = LayoutInflater.from(context);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PullZoomView);
- int zoomResId = a.getResourceId(R.styleable.PullZoomView_zoomview, 0);
- if (zoomResId > 0) {
- mZoomView = inflater.inflate(zoomResId, null, false);
- }
- int headResId = a.getResourceId(R.styleable.PullZoomView_headview, 0);
- if (headResId > 0) {
- mHeadView = inflater.inflate(headResId, null, false);
- }
- initHeader(a);
- a.recycle();
- addView(mRootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (!isPullEnable() || isHeadHide()) {
- return false;
- }
- int action = ev.getAction();
- if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
- isDragging = false;
- return false;
- }
- if (action != MotionEvent.ACTION_DOWN && isDragging) {
- return true;
- }
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- if (allowStart()) {
- mLastX = mInitX = ev.getX();
- mLastY = mInitY = ev.getY();
- isDragging = false;
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (allowStart()) {
- float x = ev.getX();
- float y = ev.getY();
- float diffX = x - mLastX;
- float diffY = y - mLastY;
- float diffYAds = Math.abs(diffY);
- if (diffYAds > mTouchSlop && diffYAds > Math.abs(diffX)) {
- if (diffY >= 1 && allowStart()) {
- mLastX = x;
- mLastY = y;
- isDragging = true;
- }
- }
- }
- break;
- }
- return isDragging;
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!isPullEnable || isHeadHide()) {
- return false;
- }
- if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
- return false;
- }
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (allowStart()) {
- mLastX = mInitX = event.getX();
- mLastY = mInitY = event.getY();
- return true;
- }
- break;
- case MotionEvent.ACTION_MOVE:
- if (allowStart()) {
- mLastX = event.getX();
- mLastY = event.getY();
- final int newScrollValue = Math.round(Math.min(mInitY - mLastY, 0) / 2.0f);
- pull(newScrollValue);
- return true;
- }
- break;
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- if (isDragging) {
- isDragging = false;
- smoothRestore();
- }
- break;
- }
- return false;
- }
- public boolean isPullEnable() {
- return isPullEnable;
- }
- public void setIsPullEnable(boolean isPullEnable) {
- this.isPullEnable = isPullEnable;
- }
- public boolean isHeadHide() {
- return isHeadHide;
- }
- public void setIsHeadHide(boolean isHeadHide) {
- this.isHeadHide = isHeadHide;
- }
- /**
- * 创建根布局,例如ListView,GridView,RecycleView,ScrollView等等
- *
- * @param context
- * @param set
- * @return
- */
- public abstract T initRootView(Context context, AttributeSet set);
- /**
- * 判定是否允许开始滚动
- *
- * @return
- */
- public abstract boolean allowStart();
- /**
- * 传入一个计算值,用来对Header做放大缩小操作
- *
- * @param value
- */
- public abstract void pull(int value);
- /**
- *
- */
- public abstract void smoothRestore();
- }
PullZoomListView.java
- public class PullZoomListView extends PullZoomBase<ListView> {
- private FrameLayout mHeaderContainer;
- private int mHeaderHeight;
- private SmoothRestore mSmoothRestore;
- public static Interpolator mInterpolator = new Interpolator() {
- @Override
- public float getInterpolation(float input) {
- float f = input - 1.0F;
- return 1.0F + f * (f * (f * (f * f)));
- }
- };
- public PullZoomListView(Context context) {
- this(context, null);
- }
- public PullZoomListView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public PullZoomListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- mSmoothRestore = new SmoothRestore();
- }
- @Override
- public ListView initRootView(Context context, AttributeSet set) {
- ListView listview = new ListView(context, set);
- return listview;
- }
- @Override
- public void initHeader(TypedArray a) {
- mHeaderContainer = new FrameLayout(getContext());
- if (mZoomView != null) {
- mHeaderContainer.addView(mZoomView);
- }
- if (mHeadView != null) {
- mHeaderContainer.addView(mHeadView);
- }
- mRootView.addHeaderView(mHeaderContainer);
- }
- public void setAdapter(BaseAdapter adapter) {
- mRootView.setAdapter(adapter);
- }
- public void setHeaderLayoutParams(AbsListView.LayoutParams params) {
- if (mHeaderContainer != null) {
- mHeaderContainer.setLayoutParams(params);
- mHeaderHeight = params.height;
- }
- }
- public void updateHeader() {
- if (mHeaderContainer != null) {
- mRootView.removeHeaderView(mHeaderContainer);
- mHeaderContainer.removeAllViews();
- if (mZoomView != null) {
- mHeaderContainer.addView(mZoomView);
- }
- if (mHeadView != null) {
- mHeaderContainer.addView(mHeadView);
- }
- mHeaderHeight = mHeaderContainer.getHeight();
- mRootView.addHeaderView(mHeaderContainer);
- }
- }
- @Override
- public boolean allowStart() {
- return isFirstItemVisiable();
- }
- private boolean isFirstItemVisiable() {
- Adapter adapter = mRootView.getAdapter();
- if (null == adapter || adapter.isEmpty()) {
- return true;
- } else {
- if (mRootView.getFirstVisiblePosition() <= 1) {
- View view = mRootView.getChildAt(0);
- if (view != null) {
- return view.getTop() >= mRootView.getTop();
- }
- }
- }
- return false;
- }
- @Override
- public void pull(int value) {
- if (mSmoothRestore != null && !mSmoothRestore.isFinish()) {
- mSmoothRestore.abort();
- }
- ViewGroup.LayoutParams params = mHeaderContainer.getLayoutParams();
- params.height = Math.abs(value) + mHeaderHeight;
- mHeaderContainer.setLayoutParams(params);
- }
- @Override
- public void smoothRestore() {
- mSmoothRestore.start(200L);
- }
- class SmoothRestore implements Runnable {
- protected long duration;
- protected boolean isFinished;
- protected float scale;
- protected long starttime;
- SmoothRestore() {
- }
- public void abort() {
- isFinished = true;
- }
- public boolean isFinish() {
- return isFinished;
- }
- public void start(long d) {
- if (mZoomView != null) {
- starttime = SystemClock.currentThreadTimeMillis();
- duration = d;
- scale = (float) mHeaderContainer.getBottom() / mHeaderHeight;
- isFinished = false;
- post(this);
- }
- }
- @Override
- public void run() {
- if (mZoomView != null) {
- float f2;
- ViewGroup.LayoutParams params;
- if (!isFinished && scale > 1.0D) {
- float f1 = ((float) SystemClock.currentThreadTimeMillis() - (float) starttime) / (float) duration;
- f2 = scale - (scale - 1.0F) * PullZoomListView.mInterpolator.getInterpolation(f1);
- params = mHeaderContainer.getLayoutParams();
- if (f2 > 1.0F) {
- params.height = (int) (f2 * mHeaderHeight);
- mHeaderContainer.setLayoutParams(params);
- post(this);
- return;
- }
- isFinished = true;
- }
- }
- }
- }
- }