仿QQ空间标题效果 下拉刷新 动画缩放 标题渐隐

最近项目有个我的相册功能,类似于qq空间的效果,整理下代码分享给大家。

1、重写ScrollView(其他类似ListView,recycleView类似),类文件如下(注意:我是因为布局原因,在类里面定义了两个缩放View,如无特殊要求一个就可以了,而且禁止了宽度的缩放,只允许竖直缩放,大家有新需求可以修改)

/**
 * 阻尼效果的scrollview
 */

public class DampScrollView extends ScrollView {
    public DampScrollView(Context context) {
        super(context);
    }

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

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

    //    用于记录下拉位置
    private float y = 0f;
    //    zoomView原本的宽高
    private int zoomViewWidth = 0;
    private int zoomViewHeight = 0;
    private int layoutWidth = 0;
    private int layoutHeight = 0;
    //上拉的距离
    private int distance;
    //    是否正在放大
    private boolean mScaling = false;

    //    放大的view,默认为第一个子view
    private View zoomView;
    private View layout;

    public void setZoomView(View zoomView, View layout) {
        this.zoomView = zoomView;
        this.layout = layout;
    }

    //    滑动放大系数,系数越大,滑动时放大程度越大
    private float mScaleRatio = 0.4f;

    public void setmScaleRatio(float mScaleRatio) {
        this.mScaleRatio = mScaleRatio;
    }

    //    最大的放大倍数
    private float mScaleTimes = 2f;

    public void setmScaleTimes(int mScaleTimes) {
        this.mScaleTimes = mScaleTimes;
    }

    //    回弹时间系数,系数越小,回弹越快
    private float mReplyRatio = 0.5f;

    public void setmReplyRatio(float mReplyRatio) {
        this.mReplyRatio = mReplyRatio;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
//        不可过度滚动,否则上移后下拉会出现部分空白的情况
        setOverScrollMode(OVER_SCROLL_NEVER);
//        获得默认第一个view
        if (getChildAt(0) != null && getChildAt(0) instanceof ViewGroup && zoomView == null) {
            ViewGroup vg = (ViewGroup) getChildAt(0);
            if (vg.getChildCount() > 0) {
                zoomView = vg.getChildAt(0);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (zoomViewWidth <= 0 || zoomViewHeight <= 0) {
            zoomViewWidth = zoomView.getMeasuredWidth();
            zoomViewHeight = zoomView.getMeasuredHeight();
            layoutWidth = layout.getMeasuredWidth();
            layoutHeight = layout.getMeasuredHeight();
        }
        if (zoomView == null || zoomViewWidth <= 0 || zoomViewHeight <= 0) {
            return super.onTouchEvent(ev);
        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_MOVE:
                if (!mScaling) {
                    if (getScrollY() == 0) {
                        y = ev.getY();//滑动到顶部时,记录位置
                    } else {
                        break;
                    }
                }
                distance = (int) ((ev.getY() - y) * mScaleRatio);
                if (distance < 0) break;//若往下滑动
                mScaling = true;
                setZoom(distance);
                return true;
            case MotionEvent.ACTION_UP:
                mScaling = false;
                replyView();
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 放大view
     */
    private void setZoom(float s) {
        float scaleTimes = (float) ((zoomViewWidth + s) / (zoomViewWidth * 1.0));
//        如超过最大放大倍数,直接返回
        if (scaleTimes > mScaleTimes) return;

        ViewGroup.LayoutParams layoutParams = zoomView.getLayoutParams();
        ViewGroup.LayoutParams layoutParams1 = layout.getLayoutParams();
        //layoutParams.width = (int) (zoomViewWidth + s);
        layoutParams.height = (int) (zoomViewHeight * ((zoomViewWidth + s) / zoomViewWidth));
        layoutParams1.height = (int) (layoutHeight * ((layoutWidth + s) / layoutWidth));
//        设置控件水平居中
        //((MarginLayoutParams) layoutParams).setMargins(-(layoutParams.width - zoomViewWidth) / 2, 0, 0, 0);
        zoomView.setLayoutParams(layoutParams);
        layout.setLayoutParams(layoutParams1);

        if (s > zoomViewHeight / 3.0) {
            if (refreshListerer != null)
                refreshListerer.startRefresh();
        }
    }

    /**
     * 回弹
     */
    private void replyView() {
        if (refreshListerer != null)
            if (distance > zoomViewHeight / 3.0)
                refreshListerer.getData();
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if (onScrollListener != null) onScrollListener.onScroll(l, t, oldl, oldt);
    }

    private OnScrollListener onScrollListener;

    public void setOnScrollListener(OnScrollListener onScrollListener) {
        this.onScrollListener = onScrollListener;
    }

    private RefreshListerer refreshListerer;

    public void setRefreshListener(RefreshListerer refreshListerer) {
        this.refreshListerer = refreshListerer;
    }

    /**
     * 滑动监听
     */
    public interface OnScrollListener {
        void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY);
    }

    /**
     * 刷新监听
     */
    public interface RefreshListerer {
        void startRefresh();

        void getData();
    }

    /**
     * 开启回弹动画
     */
    public void startAntimation() {
        final float distance = zoomView.getMeasuredHeight() - zoomViewHeight;
        // 设置动画
        ValueAnimator anim = ObjectAnimator.ofFloat(distance, 0.0F).setDuration((long) (distance * mReplyRatio));
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                setZoom((Float) animation.getAnimatedValue());
            }
        });
        anim.start();
    }
}

2、主Activity代码如下

public class MyPhotoActivity extends BaseActivity implements DampScrollView.RefreshListerer {
    private DampScrollView scroll_view;
    private RoundedImageView imageView;
    private RelativeLayout root, relative;
    private MyListView listView;
    private MyPhotoAdapter adapter;
    private TitleBarBuilder builder;

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.my_photo);
        initTitleBar();
        initView();
        monitor();
    }

    private void initTitleBar() {
        builder = new TitleBarBuilder(this);
        builder.setTitle("我的相册").setAlpha(0).setImageLeftRes(R.mipmap.back).setLeftListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                finish();
            }
        }).setImageRightRes(R.mipmap.btn_add).setRightListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ToastUtils.showShort(MyPhotoActivity.this, "右边操作");
            }
        });
    }

    private void initView() {
        scroll_view = (DampScrollView) findViewById(R.id.scroll_view);
        scroll_view.setRefreshListener(this);
        root = (RelativeLayout) findViewById(R.id.root);
        imageView = (RoundedImageView) findViewById(R.id.imageView);
        listView = (MyListView) findViewById(R.id.listView);
        relative = (RelativeLayout) findViewById(R.id.relative);
        scroll_view.setZoomView(imageView, relative);

        adapter = new MyPhotoAdapter(this);
        listView.setAdapter(adapter);
    }

    @Override
    protected void onResume() {
        super.onResume();
        root.setFocusable(true);
        root.setFocusableInTouchMode(true);
        root.requestFocus();
    }

    private void monitor() {
        scroll_view.setOnScrollListener(new DampScrollView.OnScrollListener() {
            @Override
            public void onScroll(int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
                if (scrollY < 500) {
                    float alpha = ((float) scrollY) / 500;
                    builder.setAlpha(alpha);
                } else {
                    builder.setAlpha(1);
                }
            }
        });
    }

    @Override
    public void startRefresh() {
        builder.setProgress(View.VISIBLE);
    }

    Handler handler = new Handler();

    @Override
    public void getData() {
        //模拟请求数据
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                builder.setProgress(View.GONE);
            }
        }, 2000);
        scroll_view.startAntimation();
    }
}

3、TitleBarBuilder是我项目里面的一个获取标题布局id的工具类,大家也可以在activity获取控件id,代码如下

public class TitleBarBuilder {
    protected RelativeLayout leftLayout, root;
    protected ImageView leftImage;
    private TextView leftTv;
    protected RelativeLayout rightLayout;
    protected ImageView rightImage;
    private TextView rightTv;
    protected TextView titleView;
    protected RelativeLayout titleLayout;
    private ProgressBar progressbar;
    public TitleBarBuilder(Activity context) {
        root = (RelativeLayout) context.findViewById(R.id.root);
        leftLayout = (RelativeLayout) context.findViewById(R.id.left_layout);
        leftImage = (ImageView) context.findViewById(R.id.left_image);
        leftTv = (TextView) context.findViewById(R.id.left_tv);
        rightLayout = (RelativeLayout) context.findViewById(R.id.right_layout);
        rightImage = (ImageView) context.findViewById(R.id.right_image);
        rightTv = (TextView) context.findViewById(R.id.right_tv);
        titleView = (TextView) context.findViewById(R.id.title);
        progressbar = (ProgressBar) context.findViewById(R.id.progressbar);
        titleLayout = (RelativeLayout) context.findViewById(R.id.root);
    }

    public TitleBarBuilder(View context) {
        root = (RelativeLayout) context.findViewById(R.id.root);
        leftLayout = (RelativeLayout) context.findViewById(R.id.left_layout);
        leftImage = (ImageView) context.findViewById(R.id.left_image);
        leftTv = (TextView) context.findViewById(R.id.left_tv);
        rightLayout = (RelativeLayout) context.findViewById(R.id.right_layout);
        rightImage = (ImageView) context.findViewById(R.id.right_image);
        rightTv = (TextView) context.findViewById(R.id.right_tv);
        titleView = (TextView) context.findViewById(R.id.title);
        titleLayout = (RelativeLayout) context.findViewById(R.id.root);
        progressbar = (ProgressBar) context.findViewById(R.id.progressbar);
    }

    public TitleBarBuilder setTitle(String str) {
        titleView.setText(str);
        return this;
    }

    public TitleBarBuilder setTextLeft(String str) {
        leftTv.setVisibility(View.VISIBLE);
        leftLayout.setVisibility(View.VISIBLE);
        leftTv.setText(str);
        return this;
    }

    public TitleBarBuilder setTextRight(String str) {
        rightTv.setVisibility(View.VISIBLE);
        rightLayout.setVisibility(View.VISIBLE);
        rightTv.setText(str);
        return this;
    }

    public TitleBarBuilder setImageLeftRes(int res) {
        leftImage.setVisibility(View.VISIBLE);
        leftLayout.setVisibility(View.VISIBLE);
        leftImage.setImageResource(res);
        return this;
    }

    public TitleBarBuilder setImageRightRes(int res) {
        rightImage.setVisibility(View.VISIBLE);
        rightLayout.setVisibility(View.VISIBLE);
        rightImage.setImageResource(res);
        return this;
    }

    public TitleBarBuilder setLeftListener(View.OnClickListener listener) {
        if (leftTv.getVisibility() == View.VISIBLE || leftImage.getVisibility() == View.VISIBLE) {
            leftLayout.setOnClickListener(listener);
        }
        return this;
    }

    public TitleBarBuilder setRightListener(View.OnClickListener listener) {
        if (rightTv.getVisibility() == View.VISIBLE || rightImage.getVisibility() == View.VISIBLE) {
            rightLayout.setOnClickListener(listener);
        }
        return this;
    }

    public TitleBarBuilder setTitleBarBackGround(int res) {
        root.setBackgroundResource(res);
        return this;
    }

    public TitleBarBuilder setAlpha(float alpha){
        root.getBackground().setAlpha((int)(alpha*255));
        return this;
    }

    public TitleBarBuilder setProgress(int visibility){
        progressbar.setVisibility(visibility);
        return this;
    }
}

4、titlebar的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:background="@drawable/gradient_bg"
    android:paddingTop="10dp"
    android:gravity="center_vertical">

    <RelativeLayout
        android:id="@+id/left_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:padding="8dp"
        android:layout_centerVertical="true"
        android:background="@drawable/ease_common_tab_bg"
        android:clickable="true">

        <TextView
            android:id="@+id/left_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="invisible" />

        <ImageView
            android:id="@+id/left_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:scaleType="centerInside"
            />
    </RelativeLayout>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:clickable="true">
        <ProgressBar
            android:id="@+id/progressbar"
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:layout_toLeftOf="@+id/title"
            android:visibility="gone"
            android:indeterminate="false"
            android:indeterminateDrawable="@drawable/progressbar" />
        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textColor="@android:color/white"
            android:textSize="18sp" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/right_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:padding="8dp"
        android:layout_centerVertical="true"
        android:background="@drawable/ease_common_tab_bg">

        <TextView
            android:id="@+id/right_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="invisible" />

        <ImageView
            android:id="@+id/right_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:scaleType="centerInside" />
    </RelativeLayout>

</RelativeLayout>

5、主Activity布局

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/white"
    android:orientation="vertical">

    <com.qcwl.debo.view.DampScrollView
        android:id="@+id/scroll_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/white"
        android:orientation="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content">

                    <com.qcwl.debo.view.RoundedImageView
                        android:id="@+id/imageView"
                        android:layout_width="match_parent"
                        android:layout_height="250dp"
                        android:background="@mipmap/wish_star_bg"
                        android:scaleType="centerCrop"
                        app:mutate_background="false"
                        app:oval="false" />

                </LinearLayout>


                <RelativeLayout
                    android:id="@+id/relative"
                    android:layout_width="match_parent"
                    android:layout_height="250dp"
                    android:layout_marginTop="100dp">

                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content">

                        <TextView
                            android:id="@+id/name"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_above="@+id/sign"
                            android:layout_below="@+id/imageView"
                            android:layout_marginBottom="25dp"
                            android:layout_toLeftOf="@+id/image"
                            android:text="洛神"
                            android:textColor="@android:color/black"
                            android:textSize="16sp" />

                        <com.qcwl.debo.view.RoundedImageView
                            android:id="@+id/image"
                            android:layout_width="90dp"
                            android:layout_height="90dp"
                            android:layout_above="@+id/sign"
                            android:layout_alignParentRight="true"
                            android:layout_marginBottom="10dp"
                            android:layout_marginLeft="10dp"
                            android:layout_marginRight="15dp"
                            android:scaleType="centerCrop"
                            android:src="@mipmap/em_default_avatar"
                            app:border_color="@android:color/white"
                            app:border_width="2dp"
                            app:corner_radius="5dip"
                            app:mutate_background="false"
                            app:oval="true" />

                        <TextView
                            android:id="@+id/sign"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_alignParentBottom="true"
                            android:layout_alignParentRight="true"
                            android:paddingBottom="10dp"
                            android:layout_marginBottom="5dp"
                            android:layout_marginLeft="140dp"
                            android:layout_marginRight="15dp"
                            android:gravity="right"
                            android:text="偏弱蛟龙,宛若游龙,仿佛兮若青云之蔽月,飘摇兮若流风之回雪"
                            android:textColor="@android:color/black"
                            android:textSize="12sp" />
                    </RelativeLayout>

                </RelativeLayout>

            </RelativeLayout>

            <com.qcwl.debo.view.MyListView
                android:id="@+id/listView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>

    </com.qcwl.debo.view.DampScrollView>

    <include layout="@layout/title_bar" />
</FrameLayout>

RoundedImageView 是我自定义的控件,换成普通ImageView就可以了

6、下面附上效果图
这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

7、如遇项目资源报错,一般是资源文件,换成自己的或者系统的就可以了,上图效果为沉浸式,别忘记在activity加入沉浸式,效果好一些


    /**
     * 沉浸式状态栏
     */
    private void initState() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            //透明状态栏
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
            //透明导航栏
            //getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
        }
    }

在activity的onCreate方法加入就可以。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值