您的位置:首页 > 移动开发 > Android开发

Android自定义控件——PullZoomView

2016-01-15 00:24 477 查看
本文介绍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;
                }

            }
        }
    }
}


GitHub:https://github.com/gumingwei/pullzoom
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: