关闭

listview scrollview 头部下拉放大效果

标签: listviewscrollviewheader缩放
311人阅读 评论(0) 收藏 举报

目前市面上很多app都有头部图片下啦放大效果
下面介绍一下实现方式
主要用的技术点事件分发和属性动画
上代码

 package com.example.apple.pullzoom;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import java.io.BufferedReader;
import java.io.CharArrayReader;

/**
 * Created by apple on 16/8/23.
 */
public abstract class PullZoomBase<T extends View> extends LinearLayout {


    protected T rootView;
    protected int mScreenHeight;
    protected int mScreenWidth;
    boolean flag = true;
    private float lastX, lastY;
    private float mTouchSlop;//滑动最小偏移量

    public PullZoomBase(Context context) {
        this(context, null);

    }

    public PullZoomBase(Context context, AttributeSet attrs) {
        super(context, attrs);
        ViewConfiguration config = ViewConfiguration.get(context);
        mTouchSlop = config.getScaledTouchSlop();

        rootView = getView();
        DisplayMetrics localDisplayMetrics = new DisplayMetrics();
        ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(localDisplayMetrics);
        mScreenHeight = localDisplayMetrics.heightPixels;
        mScreenWidth = localDisplayMetrics.widthPixels;
        init();


        this.addView(rootView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    public PullZoomBase(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:

                if (isPullStart()) {
                    lastX = ev.getX();
                    lastY = ev.getY();
                    flag = false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (isPullStart()) {
                    float cx = ev.getX(), cy = ev.getY();
                    float offsetY, offsetx;
                    offsetx = cx - lastX;
                    offsetY = cy - lastY;
                    if (offsetY > mTouchSlop && Math.abs(offsetY) > Math.abs(offsetx)) {
                        if (offsetY > 0 && isPullStart()) {
                            lastY = cy;
                            lastX = cx;
                            flag = true;
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                flag = false;
                break;

        }
        return flag;


    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (isPullStart()) {
                    stopScroll();
                    lastY = event.getY();
                    lastX = event.getX();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                pollZoom(event);

                break;

            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:

                scrolltotop();
                break;
        }
        return super.onTouchEvent(event);
    }

    public void pollZoom(MotionEvent event) {
        float offset = lastY - event.getY();
        headerZoom(Math.abs(Math.min(offset, 0)) / 2);

    }

    public abstract void headerZoom(float offset);

    protected abstract void scrolltotop();

    public abstract T getView();

    public abstract void init();

    protected abstract boolean isPullStart();

    protected abstract void stopScroll();


}

onInterceptTouchEvent 事件分发
isPullStart() 判断当前滑动的是否需要放大header,判断事件是否需要自己消耗。
getScrollY() 获取的是滑动到屏幕外的值,当getScrollY() ==0 这个时候向下拉,就放大header,当松开手的时候,调用属性动画,恢复到以前的高度



 package com.example.apple.pullzoom;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ScrollView;

/**
 * Created by apple on 16/8/23.
 */
public class ScrollViewPullZoom extends PullZoomBase<ScrollView> {

    FrameLayout headerView;
    LinearLayout centerView;
    int headerHight;
    ValueAnimator valueanimator;

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

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

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

    }

    @Override
    public void headerZoom(float offset) {
        ViewGroup.LayoutParams layoutParams = headerView.getLayoutParams();
        layoutParams.height = (int) (headerHight + offset);
        headerView.setLayoutParams(layoutParams);

    }

    public void stopScroll() {
        if (valueanimator != null && valueanimator.isRunning()) {

            valueanimator.cancel();

        }

    }


    @Override
    protected void scrolltotop() {

        int botton = headerView.getBottom();

        valueanimator = ValueAnimator.ofFloat(botton, botton - headerHight).setDuration(200);

        valueanimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float c = (float) animation.getAnimatedValue();
                ViewGroup.LayoutParams layoutParams = headerView.getLayoutParams();
                layoutParams.height = Math.max((int) c, headerHight);
                headerView.setLayoutParams(layoutParams);
            }
        });
        valueanimator.setInterpolator(new AccelerateInterpolator());
        valueanimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        valueanimator.start();


    }

    @Override
    public ScrollView getView() {

        MyScrollView scrollView = new MyScrollView(getContext());

        scrollView.setOnScrollViewChangedListener(new OnScrollViewChangedListener() {
            @Override
            public void onScrollChanged(int left, int top, int oldLeft, int oldTop) {

                int h = rootView.getScrollY();
                if ((h > 0.0F) && (h < headerHight)) {
                    int i = (int) (0.5 * h);
                    headerView.scrollTo(0, -i);
                } else if (headerView.getScrollY() != 0) {
                    headerView.scrollTo(0, 0);
                }

            }
        });
        return scrollView;
    }

    @Override
    public void init() {
        headerView = new FrameLayout(getContext());
        centerView = new LinearLayout(getContext());
        centerView.setOrientation(LinearLayout.VERTICAL);

        centerView.addView(headerView);
        rootView.addView(centerView);

    }

    @Override
    public boolean isPullStart() {
        return rootView.getScrollY() == 0;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (headerHight == 0 && headerView != null) {
            headerHight = headerView.getHeight();
        }
    }

    public void setContentView(View contentview) {
        centerView.addView(contentview);
    }

    public void setZoomView(View contentview) {
        headerView.addView(contentview);
    }


    public void setHeaderLayoutParams(LayoutParams localObject) {
        headerView.setLayoutParams(localObject);
        headerHight = localObject.height;
    }

    class MyScrollView extends ScrollView {
        OnScrollViewChangedListener lis;

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

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

        @Override
        protected void onScrollChanged(int l, int t, int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
            lis.onScrollChanged(l, t, oldl, oldt);

        }

        public void setOnScrollViewChangedListener(OnScrollViewChangedListener lis) {
            this.lis = lis;
        }
    }

    protected interface OnScrollViewChangedListener {
        void onScrollChanged(int left, int top, int oldLeft, int oldTop);
    }

}

下面是listview的实现方式

package com.example.apple.pullzoom;

import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.widget.AbsListView;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;

/**
 * Created by apple on 16/8/28.
 */
public class ListViewPullZoom extends PullZoomBase<ListView> {


    final String TAG = "ListViewPullZoom";

    private int headerHight;
    private ValueAnimator mValueAnimator;

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

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

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


    FrameLayout headerView;

    @Override
    public void headerZoom(float offset) {

        ViewGroup.LayoutParams layout =   headerView.getLayoutParams();
        layout.height = (int)(headerHight + offset);
        headerView.setLayoutParams(layout);

    }

    @Override
    protected void scrolltotop() {
        int botton = headerView.getBottom();

        mValueAnimator = ValueAnimator.ofFloat(botton,botton - headerHight).setDuration(300);
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
               float cy = (float) animation.getAnimatedValue();
               ViewGroup.LayoutParams lp =  headerView.getLayoutParams();
                if(cy< headerHight ){
                    cy = headerHight;
                }
                lp.height = (int)cy;
                headerView.setLayoutParams(lp);
            }
        });
        mValueAnimator.setInterpolator(new AccelerateInterpolator());
        mValueAnimator.start();
    }

    @Override
    public ListView getView() {
        ListView listView = new ListView(getContext());
        listView.setOnScrollListener(new AbsListView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (headerView != null) {

                    int offset = headerHight - headerView.getBottom();
                    if (offset > 0) {
                        headerView.scrollTo(0, -(int) (offset * 0.5f));
                    } else {
                        if (headerView.getScrollY() != 0) {
                            headerView.scrollTo(0, 0);
                        }
                    }

                }
            }
        });


        return listView;
    }

    public void setAdapter(ListAdapter adapter) {
        rootView.setAdapter(adapter);
    }


    public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener listener) {
        rootView.setOnItemClickListener(listener);
    }


    @Override
    public void init() {

        headerView = new FrameLayout(getContext());
        rootView.addHeaderView(headerView);

    }

    @Override
    protected boolean isPullStart() {
        return isFirstItemVisible();
    }

    private boolean isFirstItemVisible() {
        final Adapter adapter = rootView.getAdapter();

        if (null == adapter || adapter.isEmpty()) {
            return true;
        } else {
            if (rootView.getFirstVisiblePosition() <= 0) {
                final View firstVisibleChild = rootView.getChildAt(0);
                if (firstVisibleChild != null) {
                    return firstVisibleChild.getTop() >= rootView.getTop();
                }
            }
        }

        return false;
    }


    @Override
    protected void stopScroll() {
        if(mValueAnimator != null && mValueAnimator.isRunning()){
            mValueAnimator.cancel();
        }
    }

    public void setZoomView(View zoomView) {

        this.headerView.addView(zoomView);
    }

    public void setHeaderLayoutParams(AbsListView.LayoutParams headerLayoutParams) {

        headerView.setLayoutParams(headerLayoutParams);
        headerHight = headerLayoutParams.height;
    }
}
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:407次
    • 积分:23
    • 等级:
    • 排名:千里之外
    • 原创:2篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章存档