十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
Android中怎么自定义一个底部上拉控件,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
创新互联建站专注为客户提供全方位的互联网综合服务,包含不限于网站设计制作、网站制作、广灵网络推广、成都小程序开发、广灵网络营销、广灵企业策划、广灵品牌公关、搜索引擎seo、人物专访、企业宣传片、企业代运营等,从售前售中售后,我们都将竭诚为您服务,您的肯定,是我们最大的嘉奖;创新互联建站为所有大学生创业者提供广灵建站搭建服务,24小时服务热线:18982081108,官方网址:www.cdcxhl.com
1. 在Project的build.gradle文件中添加:
allprojects { repositories { ... maven { url 'https://jitpack.io' } } }
2.在Module的build.gradle文件中添加:
dependencies { compile 'com.github.qingmei2:SlideBottomLayout-Android:1.2.3' }
3.Add view in your layout:
需要注意的是:为了简单实现,笔者偷了个懒,设定为该布局下只能有一个直接的子View(类似ScrollView)
因此如果您添加需要一个布局,请在外面嵌套一个ViewGroup:
实现步骤
具体代码如下,其中上述需求的设置方式都已经在代码中声明:
先看下属性声明:
public class SlideBottomLayout extends LinearLayout { public void setShortSlideListener(ShortSlideListener listener) { this.shortSlideListener = listener; } private ShortSlideListener shortSlideListener; /** * The {@link MotionEvent#ACTION_DOWN} gesture location. */ private int downY; /** * The {@link MotionEvent#ACTION_MOVE} gesture location. */ private int moveY; /** * the value of moved distance by the gesture. When the value was modified and not exceed * the {@link #movedMaxDis}, then make this ViewGroup move. */ private int movedDis; /** * The max distance that the {@link SlideBottomLayout} can scroll to, it used to compare with the * {@link #downY}, determine whether it can slide by the gesture. */ private int movedMaxDis; /** * ChildView of the {@link SlideBottomLayout}, you can set a Layout such as the {@link LinearLayout}、 * {@link android.widget.RelativeLayout} ect. * We set the rules that {@link SlideBottomLayout} just can have one child-view, or else get a * {@link RuntimeException} at {@link #onFinishInflate()} */ private View childView; /** * The control {@link SlideBottomLayout} automatically switches the threshold of the state. if * this ViewGroup moved distance more than {@link #movedMaxDis} * it, switch the state of * {@link #arriveTop} right now. * * See the {@link #touchActionUp(float)}. */ private float hideWeight = 0.25f; //3.注意,这个接口用来设置「需要自定义自动到达顶部/隐藏的阈值」 public void setHideWeight(float hideWeight) { if (hideWeight <= 0 || hideWeight > 1) throw new IllegalArgumentException("hideWeight should belong (0f,1f]"); this.hideWeight = hideWeight; } private Scroller mScroller; /** * It means the {@link #childView} is arriving the top of parent or else. */ private boolean arriveTop = false; /** * the {@link #childView} Initially visible height */ private float visibilityHeight; //1.初始化Handle显示高度,建议您在xml中设置对应属性来实现该效果 public void setVisibilityHeight(float visibilityHeight) { this.visibilityHeight = visibilityHeight; } public SlideBottomLayout(@NonNull Context context) { super(context); } public SlideBottomLayout(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); initAttrs(context, attrs); } public SlideBottomLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initAttrs(context, attrs); } /** * Get the config from {@link R.styleable}, then init other configrations{@link #initConfig(Context)}. * * @param context the {@link Context} * @param attrs the configs in layout attrs. */ private void initAttrs(Context context, AttributeSet attrs) { final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlideBottomLayout); visibilityHeight = ta.getDimension(R.styleable.SlideBottomLayout_handler_height, 0); ta.recycle(); initConfig(context); } private void initConfig(Context context) { if (mScroller == null) mScroller = new Scroller(context); this.setBackgroundColor(Color.TRANSPARENT); } /** * It start a judgement for ensure the child-view be unique in this method,then assgin it * to {{@link #childView}. * this method will be called before the {@link #onMeasure(int, int)} */ @Override protected void onFinishInflate() { super.onFinishInflate(); if (getChildCount() == 0 || getChildAt(0) == null) { throw new RuntimeException("there have no child-View in the SlideBottomLayout!"); } if (getChildCount() > 1) { throw new RuntimeException("there just alow one child-View in the SlideBottomLayout!"); } childView = getChildAt(0); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); movedMaxDis = (int) (childView.getMeasuredHeight() - visibilityHeight); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); childView.layout(0, movedMaxDis, childView.getMeasuredWidth(), childView.getMeasuredHeight() + movedMaxDis); } @Override public boolean onTouchEvent(MotionEvent event) { final float dy = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (touchActionDown(dy)) return true; break; case MotionEvent.ACTION_MOVE: if (touchActionMove(dy)) return true; break; case MotionEvent.ACTION_UP: if (touchActionUp(dy)) return true; break; } return super.onTouchEvent(event); } @Override public void computeScroll() { super.computeScroll(); if (mScroller == null) mScroller = new Scroller(getContext()); if (mScroller.computeScrollOffset()) { scrollTo(0, mScroller.getCurrY()); postInvalidate(); } } /** * When the touch event is {@link MotionEvent#ACTION_UP}, * then judge the state of view group and control the {@link Scroller} to scroll. ** In this ViewGroup, we set the rules that is if this scroll gesture's move distance * more than {@link #movedMaxDis} * {@link #hideWeight}(default hideWeight value is 1/4 heights * of this ViewGroup), then call {@link #hide()} or {@link #show()} right now. which method will * be call depends on {@link #arriveTop}. *
movedMaxDis * hideWeight) { switchVisible(); } else { if (shortSlideListener != null) { shortSlideListener.onShortSlide(eventY); } else { hide(); } } return true; } /** * When the touch event is {@link MotionEvent#ACTION_MOVE}, * then judge the state of view group and control the {@link Scroller} to scroll. *
* In this ViewGroup, we set the rules that is if this scroll gesture's move distance * more than {@link #movedMaxDis} * {@link #hideWeight}(default hideWeight value is 1/4 heights of this ViewGroup), * then call {@link #hide()} or {@link #show()} right now. *
* * @param eventY The location of trigger * @return Be used to determine consume this event or else. */ public boolean touchActionMove(float eventY) { moveY = (int) eventY; //the dy is sum of the move distance, the value > 0 means scroll up, the value < 0 means scroll down. final int dy = downY - moveY; if (dy > 0) { //scroll up movedDis += dy; if (movedDis > movedMaxDis) movedDis = movedMaxDis; if (movedDis < movedMaxDis) { scrollBy(0, dy); downY = moveY; return true; } } else { //scroll down movedDis += dy; if (movedDis < 0) movedDis = 0; if (movedDis > 0) { scrollBy(0, dy); } downY = moveY; return true; } return false; } /** * When the touch event is {@link MotionEvent#ACTION_DOWN}, * Record the location of this action. * * @param eventY The location of trigger * @return Be used to determine consume this event or else. */ public boolean touchActionDown(float eventY) { downY = (int) eventY; //Whether custom this gesture. if (!arriveTop && downY < movedMaxDis) { return false; } else return true; } /** * the extand method for showing {@link SlideBottomLayout} */ public void show() { scroll2TopImmediate(); } /** * the extand method for hiding {@link SlideBottomLayout} */ public void hide() { scroll2BottomImmediate(); } /** * @return The ViewGroup is arrive top or else. */ public boolean switchVisible() { if (arriveTop()) hide(); else show(); return arriveTop(); } public boolean arriveTop() { return this.arriveTop; } public void scroll2TopImmediate() { mScroller.startScroll(0, getScrollY(), 0, (movedMaxDis - getScrollY())); invalidate(); movedDis = movedMaxDis; arriveTop = true; } public void scroll2BottomImmediate() { mScroller.startScroll(0, getScrollY(), 0, -getScrollY()); postInvalidate(); movedDis = 0; arriveTop = false; } }
看完上述内容,你们掌握Android中怎么自定义一个底部上拉控件的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!