Android用Scroller实现一个可向上滑动的底部导航栏

静静等了5分钟竟不知道如何写我这第一篇文章。每次都想好好的学习学习,有时间多敲敲代码,写几篇自己的文章。今天终于开始实行了,还是有点小激动的。哈哈!

好了废话就不多收了。我今天想实现的一个功能就是一个可以上滑底部菜单栏。为什么我会想搞这么个东西呢, 还是源于一年前,我们app 有这么个需求,当时百度也好谷歌也好,都没有找到想要的效果,其实很简单的一个效果。但是当时我也是真的太菜了,所有有关自定义的控件真的是不会,看别人的代码还好,真要是自己写,一点头绪都没有。因为我试着写了,真的不行啊。当时觉得自己好废啊 ,所有效果都是别人的,自己都不会写。也下定决定要好好搞自定义控件,一拖再拖就到了现在。在了解了一段时间的自定义控件后又想起来这个效果,然后给他搞了出来。

看下效果:

首先这个控件是滑动的肯定就会用到scrollTo()或者scrollBy(),和Scroller类。那么先简单介绍一点这三个东西。

scrollTo(int, int)与scrollBy(int, int)

scrollTo是让View的content滚动到相对View初始位置的(x, y)处。 scrollBy是让View的content滚动到相对于View当前位置的(x, y)处。

Scroller类

Scroller是手指滑动中比较重要的一个辅助类,它可以帮助开发者完成一个顺滑的滚动。其主要包括:

startScroll(int startX, int startY, int dx, int dy)和startScroll(int startX, int - startY, int dx, int dy, int duration)。 startX,x方向从哪里开始移动。 startY,y方向从哪里开始移动。 dx,x方向移动多远。 dy,y方向移动多远。 duration,这个移动操作需要多少时间执行完,默认是250毫秒。

如果真正的想使用这个类,还需要配合computeScroll()方法。重写此方法

@Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // 计算新位置,并判断上一个滚动是否完成。 scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); invalidate();// 再次调用computeScroll。 } }

computeScrollOffset()

这个方法用来计算当前你想知道的一个新位置,Scroller会自动根据标记时的坐标、时间、当前位置计算出一个新位置,记录到内部,我们可以通过Scroller#getCurrX()和Scroller#getCurrY()获取的新的位置。

要知道的是,它计算出的新位置是一个闭区间[x, y],而且会在你调用startScroll传入的时间内渐渐从你指定的int startX和int startY移动int dx和int dy的距离,所以我们每次调用Scroller#computeScrollOffset()后再调用View的scrollTo(int, int)然后传入Scroller#getCurrX()和Scroller#getCurrY()就可以得到一个渐渐移动的效果。

同时这个方法有一个返回值是boolean类型的,内部是用一个boolean来记录是否完成的,在调用Scroller#startScroll)时会把这个boolean参数置为false。内部逻辑是先判断startScroll()动画是否还在继续,如果没有完成则计算最新位置,计算最新位置前会对duration做判断,第一如果时间没到,则真正的计算位置,并且返回true,第二如果时间到了,把记录是否继续的boolean成员变量标记完成,并直接赋值最新位置为最终目的位置,并且返回true;如果startScroll()已经完成则直接返回false。我们判断Scroller#computeScrollOffset()是true时说明还没完成,此时拿到Scroller#getCurrX()和Scroller#getCurrY()做一个滚动。

Scroller#getCurrX()

Scroller#getCurrY()

这两个方法就是拿到通过Scroller#computeScrollOffset()计算出的新的位置,上面也解释过了。

Scroller.isFinished()上次的动画是否完成。

Scroller.abortAnimation()取消上次的动画。

好了,了解了这些下面开始实现这个效果。

首先先搞一个布局,包括底部导航栏的头和导航栏的内容体。

<com.study.androidtest.BottomBar android:orientation="vertical" android:layout_alignParentBottom="true" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:background="@color/colorAccent" android:layout_width="match_parent" android:layout_height="50dp"> </LinearLayout> <LinearLayout android:background="@color/colorPrimaryDark" android:layout_width="match_parent" android:layout_height="200dp"> </LinearLayout> </com.study.androidtest.BottomBar>

配上效果图。

很简单的一个效果(这里只看效果,不看UI啦),蓝色的就是内容,红色的就是头部。
那么我想实现一个什么效果呢,就是开始的时候是看不到蓝色部分的,点击或者滑动红色部分可以显示蓝色部分,一个上拉和下拉的效果。那么现在肯定要实现一个自定的viewGroup去实现这个布局。

首先我去建一个类BottomBar.class, 为了简单我直接用它去继承LinearLayout。重写它的onLayout()方法。因为我要去把蓝色部分隐去,只留红色部分。怎么做呢 ,代码如下:

@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); bottomBar.layout(0, getMeasuredHeight() - bottomBar.getMeasuredHeight(), getMeasuredWidth(), getMeasuredHeight()); bottomContent.layout(0, getMeasuredHeight(), getMeasuredWidth(), bottomBar.getBottom() + bottomContent.getMeasuredHeight()); }

通过onLayout()方法改变其位置让其吧蓝色部分隐藏。

接下来就是处理滑动事件了。我要按住红色部分上下滑动去显示和隐藏蓝色部分,那么肯定是要有手势识别,重写onTouchEvent(),再配合view的scrollTo()方法就可以实现这个简单的效果。

@Override public boolean onTouchEvent(MotionEvent event) { super.onTouchEvent(event); switch (event.getAction()){ case MotionEvent.ACTION_DOWN: Log.i("", "--------->x="+event.getX() + ", y="+event.getY()); downX = (int) event.getX(); downY = (int) event.getY(); break; case MotionEvent.ACTION_MOVE: int endY = (int) event.getY(); int dy = (int) (endY - downY); int toScroll = getScrollY() - dy; if(toScroll < 0){ toScroll = 0; } else if(toScroll > bottomContent.getMeasuredHeight()){ toScroll = bottomContent.getMeasuredHeight(); } scrollTo(0, toScroll); downY = (int) event.getY(); break; case MotionEvent.ACTION_UP: scrollOffset = getScrollY(); if(scrollOffset > bottomContent.getMeasuredHeight() / 2){ showNavigation(); } else { closeNavigation(); } break; } return true; }

代码就懒了没有注释,但是我会在下面解释一下,都是一些简单的逻辑,首先ACTION_DOWN里面的代码,只是记录了按下的坐标,没什么的。然后是ACTION_MOVE的代码。首先应该了解getScrollY(),它是控件滑动的距离,初始值为0。可以看到我调用scrollTo(0, toScroll),而toScroll = getScrolly() - dy;,dy是手指滑动的一个偏移量。通过了这些计算你会发现toScroll就是蓝色部分的高度。那么效果就已经实现了,很简单吧。看了之后你们会不会有这样一个疑问哈,也是我当时的一个疑问,那就是为什么我们不直接用dy也就是手指滑动的一个距离来当作toScroll 的值呢(不考虑下面对downY的赋值,单纯是手指滑动的距离)。其实是可以的,控件会随着手指滑动的。但是,当手指离开屏幕再次点击的时候,菜单又会回到原来的状态再进行滑动。那么为什么会造成这样的效果呢,仔细看过你会发现,每次点击的时候dy都是0,所以每次调用scrollTo(x, y)的时候x, y都是0,自然菜单就会回到初始位置。所以getScrollY() - dy其实就是再记录上一次的位置,使在下一次点击的时候'y'的值不是0。前提是需要每次对downY重新进行赋值。好了有了这些上拉下拉的效果就有了。但是只有这样还是不行,我们要做到它自动的弹出和收回。接下来就是ACTION_UP时做处理,我调用了showNavigation();和colseNavigation();,代码如下都是简单的逻辑不做解释。

private void showNavigation(){ int dy = bottomContent.getMeasuredHeight() - scrollOffset; mScroller.startScroll(getScrollX(), getScrollY(), 0, dy, 500); invalidate(); } private void closeNavigation(){ int dy = 0 - scrollOffset; mScroller.startScroll(getScrollX(), getScrollY(), 0, dy, 500); invalidate(); }

效果实现啦,哈哈。真的很简单。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

时间: 2024-10-27 21:07:06

Android用Scroller实现一个可向上滑动的底部导航栏的相关文章

三步搞定android应用底部导航栏

很多android应用底部都有一个底部导航栏,方便用户在使用过程中随意切换.目前常用的做法有三种:一种是使用自定义tabHost,一种是使用activityGroup,一种是结合FrameLayout实现.笔者再做了多款应用后,为了节约开发周期,封装了一个抽象类,只要三步便可完成底部栏的生成及不同页面的调用. public class ActivitycollectiondemoActivity extends ActivityCollection { /** Called when the a

Android底部导航栏实现(四)之TabLayout+ViewPager

这里简单记录一下通过TabLayout+ViewPager来实现Android底部导航栏.   布局 <?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                  xmlns:app="http://schemas.an

Android程序开发之Fragment实现底部导航栏实例代码_Android

流行的应用的导航一般分为两种,一种是底部导航,一种是侧边栏. 说明 IDE:AS,Android studio; 模拟器:genymotion; 实现的效果,见下图. 具体实现 为了讲明白这个实现过程,我们贴出来的代码多一写,这样更方便理解 [最后还会放出完整的代码实现] .看上图的界面做的比较粗糙,但实现过程的骨架都具有了,想要更完美的设计,之后自行完善吧 ^0^. 布局 通过观察上述效果图,发现任意一个选项页面都有三部分组成: 顶部去除ActionBar后的标题栏: 中间一个Fragment

Android应用底部导航栏(选项卡)实例

  现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其中各个类的作用以及资源文件就不详细解释了,还有资源图片(在该Demo中借用了其它应用程序的资源图片)也不提供了,大家可以自行更换自己需要的资源图片.直接上各个布局文件或各个类的代码: [1]  res/layout目录下的 maintabs.xml 源码: [html] view plainco

【android中级】之Android应用底部导航栏(选项卡)实例

现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其中各个类的作用以及资源文件就不详细解释了,还有资源图片(在该Demo中借用了其它应用程序的资源图片)也不提供了,大家可以自行更换自己需要的资源图片www.lovewenzhang.com.直接上各个布局文件或各个类的代码: [1]  res/layout目录下的maintabs.xml : [htm

Android实现底部导航栏功能(选项卡)

现在很多android的应用都采用底部导航栏的功能,这样可以使得用户在使用过程中随意切换不同的页面,现在我采用TabHost组件来自定义一个底部的导航栏的功能. 我们先看下该demo实例的框架图: 其中各个类的作用以及资源文件就不详细解释了,还有资源图片(在该Demo中借用了其它应用程序的资源图片)也不提供了,大家可以自行更换自己需要的资源图片.直接上各个布局文件或各个类的代码: 1. res/layout目录下的 maintabs.xml 源码: <?xml version="1.0&q

Android程序开发之Fragment实现底部导航栏实例代码

流行的应用的导航一般分为两种,一种是底部导航,一种是侧边栏. 说明 IDE:AS,Android studio; 模拟器:genymotion; 实现的效果,见下图. 具体实现 为了讲明白这个实现过程,我们贴出来的代码多一写,这样更方便理解 [最后还会放出完整的代码实现] .看上图的界面做的比较粗糙,但实现过程的骨架都具有了,想要更完美的设计,之后自行完善吧 ^0^. 布局 通过观察上述效果图,发现任意一个选项页面都有三部分组成: 顶部去除ActionBar后的标题栏: 中间一个Fragment

android中Fragment+RadioButton实现底部导航栏

在App中经常看到这样的tab底部导航栏 那么这种效果是如何实现,实现的方式有很多种,最常见的就是使用Fragment+RadioButton去实现.下面我们来写一个例子 首先我们先在activity_mian.xml定义布局,整个布局的外面是线性布局,上面是帧布局切换不同的Fragment,底下是RadioGroup嵌套的是RadioButton.代码如下所示: <?xml version="1.0" encoding="utf-8"?> <Li

Android design包自定义tablayout的底部导航栏的实现方法

以前做项目大多用的radiobutton,今天用tablayout来做一个tab切换页面的的效果. 实现的效果就是类似QQ.微信的页面间(也就是Fragment间)的切换.如图: 布局只要一个tablayout <android.support.design.widget.TabLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id=&