Android实现带进度返回顶部按钮
作者 | 被代码淹没的小伙子 地址 | https://www.jianshu.com/p/72af8f950591
效果图

1、功能
2.滑动停止:显示点击返回顶部
3.点击返回顶部
2、实现思路
(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)、记得通过LayoutParams设置ImageView大小
2)、设置ImageView在RelativeLayout中的Gravity(组件继承的是RelativeLayout),params.addRule(RelativeLayout.CENTER_IN_PARENT);(这个原来没用过)
这里主要都是通过Java代码实现的,没有通过xml实现,算是原来没有动手实现的,理解起来都比较简单,唯一需要注意的就是要细心,将该设置的属性都要设置,尤其是LayoutParams,因为是通过Java代码实现,不像xml那么直观。
3、滑动监听
public void setRecyclerView(RecyclerView recyclerView) {recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {@Overridepublic 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);}@Overridepublic 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);}
2)、通过LinearLayoutManager的getItemCount方法获得总量count
3)、通过manager.findLastVisibleItemPosition()获得当前可见的最后一个个数,也就是当前进度
源码地址:
https://github.com/DrownCoder/ToTopView
评论
