美文网首页
自定义View----带进度的返回顶部按钮

自定义View----带进度的返回顶部按钮

作者: 被代码淹没的小伙子 | 来源:发表于2017-09-25 23:51 被阅读0次
效果

记得原来一直想实现以下这样一个组件,最近抽时间完成了,花的时间也不多,实现起来也比较容易,算是自定义组件的另一种形式吧,最近入了自定义View的坑,写了好几个Demo
ToTopView
========

1.功能

1.滑动过程中:显示进度
2.滑动停止:显示点击返回顶部
3.点击返回顶部

2.实现思路

1.滑动监听:滑动状态+滑动位置
2.UI:重写RelativeLayout,实现组件的覆盖,底层:ImageView(顶部),顶层:LinearLayout(TextView(进度)+View(线)+TextView(总量))利用Java代码实现

3.关键代码理解

1.初始化函数

private void Init(Context context, AttributeSet attrs) {
        TypedArray typedArray = getContext().obtainStyledAttributes(attrs, 
                                R.styleable.ToTopView);
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.
                             ToTopView_topTextSize,DEFAULT_CONTENT_TEXT_SIZE);
        mLineColor = typedArray.getColor(R.styleable.ToTopView_lineColor,
                getResources().getColor(R.color.colorAccent));
        mBacimg = typedArray.getResourceId(R.styleable.ToTopView_btnImg,
                       R.mipmap.btn_bring_to_top);
        typedArray.recycle();
        InitView(context);
    }

三个属性可以自定义:
topTextSize:字体大小。这里要注意一点,这里返回的是px,我这里就使用的px,如果想用sp,需要将px转为sp

    public void setTextSize(float size) {  
    setTextSize(TypedValue.COMPLEX_UNIT_SP, size);
    }

可以看到,源码中如果只是setTextSize,默认是以sp为单位的。
我这里使用的是px

mTvProgress.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);

lineColor:线的颜色,也就是进度和总量中间的线的颜色
btnImg:ImageView的背景图片

2.利用Java代码绘制界面

private void InitView(Context context) {
        //图片回到顶部
        mIvTop = new ImageView(context);
        mIvTop.setImageResource(mBacimg);
        LayoutParams params = new LayoutParams(
                DensityUtils.dp2px(context, 48), DensityUtils.dp2px(context, 48));
        params.addRule(RelativeLayout.CENTER_IN_PARENT);
        mIvTop.setLayoutParams(params);
        //滑动过程中显示进度
        mLlProgress = new LinearLayout(context);
        mLlProgress.setOrientation(LinearLayout.VERTICAL);
        mLlProgress.setBackgroundResource(R.drawable.bg_totop_progress);
        LayoutParams llparams = new LayoutParams(
                DensityUtils.dp2px(context, 48), LayoutParams.MATCH_PARENT);
        mLlProgress.setLayoutParams(llparams);
        mLlProgress.setGravity(Gravity.CENTER);
        //进度
        mTvProgress = new TextView(context);
        mTvProgress.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
        mTvProgress.setGravity(Gravity.CENTER);
        LayoutParams tvparams = new LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        mTvProgress.setLayoutParams(tvparams);
        //横线
        View line = new View(context);
        line.setBackgroundColor(mLineColor);
        LayoutParams lineParams = new LayoutParams(ViewGroup.LayoutParams
                         .MATCH_PARENT, DensityUtils.dp2px(context, 1));
        line.setLayoutParams(lineParams);
        line.setPadding(DensityUtils.dp2px(context, 5), 0, 
                        DensityUtils.dp2px(context, 5), 0);
        //总量
        mTvMax = new TextView(context);
        mTvMax.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize);
        mTvMax.setGravity(Gravity.CENTER);
        mTvMax.setLayoutParams(tvparams);
        mLlProgress.addView(mTvProgress);
        mLlProgress.addView(line);
        mLlProgress.addView(mTvMax);

        addView(mIvTop);
        addView(mLlProgress);
    }

1.ImageView,都比较基础,要注意两个点:
1).记得通过LayoutParams设置ImageView大小
2).设置ImageView在RelativeLayout中的Gravity(组件继承的是RelativeLayout)
params.addRule(RelativeLayout.CENTER_IN_PARENT);(这个原来没用过)

2.LinearLayout = TextView + View + TextView
这里主要都是通过Java代码实现的,没有通过xml实现,算是原来没有动手实现的,理解起来都比较简单,唯一需要注意的就是要细心,将该设置的属性都要设置,尤其是LayoutParams,因为是通过Java代码实现,不像xml那么直观。

3.滑动监听

public void setRecyclerView(RecyclerView recyclerView) {
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (mScrollY >= getResources().getDisplayMetrics().heightPixels) {
                    setVisibility(View.VISIBLE);
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        //停止滑动
                        onShowState();
                    }
                    if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                        //滑动
                        onScrolling();
                    }
                }
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                mScrollY += dy;

                LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
                int count = manager.getItemCount();
                int lastItemPosition = manager.findLastVisibleItemPosition();
                setProgress(lastItemPosition, count);

                super.onScrolled(recyclerView, dx, dy);
            }
        });

        initEvent(recyclerView);
    }

这里我用了依赖,将RecyclerView设置给了ToTopView,这里可能设计的不太全面,后面在研究设计模式的时候再来重构一下。
1.监听滑动状态变化

public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                if (mScrollY >= getResources().getDisplayMetrics().heightPixels) {
                    setVisibility(View.VISIBLE);
                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                        //停止滑动
                        onShowState();
                    }
                    if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                        //滑动
                        onScrolling();
                    }
                }
                super.onScrollStateChanged(recyclerView, newState);
            }

如果滑动超过屏幕高度的时候后,显示组件
停止滑动时->onShowState()

    /**
     * 滑动停止
     */
    public void onShowState() {
        mIvTop.setVisibility(VISIBLE);
        mLlProgress.setVisibility(GONE);
    }

显示ImageView,隐藏LinearLayout
滑动过程中->onScrolling();

/**
     * 滑动过程中
     * 显示进度,隐藏Img
     */
    public void onScrolling() {
        mIvTop.setVisibility(GONE);
        mLlProgress.setVisibility(VISIBLE);
    }

2.监听滑动位置变化

public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                mScrollY += dy;

                LinearLayoutManager manager = (LinearLayoutManager) recyclerView
                                              .getLayoutManager();
                int count = manager.getItemCount();
                int lastItemPosition = manager.findLastVisibleItemPosition();
                setProgress(lastItemPosition, count);

                super.onScrolled(recyclerView, dx, dy);
            }

1)记录滑动距离mScrollY
2)通过LinearLayoutManager的getItemCount方法获得总量count
3)通过manager.findLastVisibleItemPosition()获得当前可见的最后一个个数,也就是当前进度

代码基本上都挺简单的,简单的写个博客记录一下,附上GitHub地址,具体代码可见GitHub
https://github.com/sdfdzx/ToTopView

相关文章

  • 自定义View----带进度的返回顶部按钮

    记得原来一直想实现以下这样一个组件,最近抽时间完成了,花的时间也不多,实现起来也比较容易,算是自定义组件的另一种形...

  • iOS 常用小控件及方法

    目录: 一, 常用小控件 自定义顶部导航CarTeamDetailsTitleView: 左侧返回按钮, 右侧更多...

  • 用vue封装一个返回顶部的按钮组件goTop.vue

    这是1个封装好的返回顶部组件 在需要使用返回顶部按钮的地方引入使用即可 如果全局都需要返回顶部按钮,直接在app....

  • 返回顶部按钮

    之前写过几次返回顶部的按钮,但是因为没有在动画结束时,使用回调函数,所以一直没发现,其实动画是执行了两次的。各大论...

  • Vue与小程序的返回顶部记录

    默认返回顶部按钮是隐藏,滚动一段距离后才显示 VUE 返回顶部 小程序 返回顶部

  • jQuery点击锚点平滑滚动

    点击锚点平滑滚动到相应页面位置: .. "返回顶部"按钮效果:向下滚动页面出现 按钮,点击返回顶部。 …………EN...

  • Vue 返回顶部

    返回顶部按钮添加goUp事件

  • 返回顶部实现

    当用户下拉一定距离,显示返回顶部按钮 监听下拉 返回顶部

  • js 返回页面顶部(动画)

    js 返回到页面顶部,含有渐变或者动画效果 点击返回顶部按钮,页面逐渐向上回到顶部: js 返回到页面顶部,直接返...

  • 系统导航右侧按钮侧滑变灰

    需求:自定义返回按钮之后,能正常使用系统侧滑返回。 问题:自定义返回按钮之后,发现侧滑返回时,系统导航右侧按钮侧滑...

网友评论

      本文标题:自定义View----带进度的返回顶部按钮

      本文链接:https://www.haomeiwen.com/subject/caejextx.html