Android自定义控件——PullZoomView

Posted 顾明伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

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

以上是关于Android自定义控件——PullZoomView的主要内容,如果未能解决你的问题,请参考以下文章

android自定义控件怎么用

[Android自定义控件] Android自定义控件

Android中的自定义控件

android自定义控件

Android自定义RatingBar(星级评分控件)

Android自定义控件1--自定义控件介绍