Android实现App中导航Tab栏悬浮的功能

作者:daisy 时间:2021-11-22 23:11:31 

首先是“饿了么”导航Tab栏悬浮的效果图。

Android实现App中导航Tab栏悬浮的功能

大家可以看到上图中的“分类”、“排序”、“筛选”会悬浮在app的顶部,状态随着ScrollView(也可能不是ScrollView,在这里姑且把这滑动的UI控件当作ScrollView吧)的滚动而变化。像这种导航Tab栏悬浮的作用相信大家都能体会到,Tab栏不会随着ScrollView等的滚动而被滑出屏幕外,增加了与用户之间的交互性和方便性。

看到上面的效果,相信大家都跃跃欲试了,那就让我们开始吧。

首先大家要明白一点:Tab栏的状态变化是要监听ScrollView滑动距离的。至于如何得到ScrollView的滑动距离?可以看看另一篇: 《Android中ScrollView实现滑动距离 * 的方法》 ,这里就不过多叙述了。

好了,根据上面的就得到了对ScrollView滑动的监听了。接下来要思考的问题就是如何让Tab栏实现悬浮的效果呢?这里给出的方法有两种,第一种就是使用WindowManager来动态地添加一个View悬浮在顶部;第二种就是随着ScrollView的滑动不断重新设置Tab栏的布局位置。

我们先来看看第一种实现方法,首先是xml布局了。

Activity的布局,activity_main.xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">

<RelativeLayout
   android:id="@+id/rl_title"
   android:layout_width="match_parent"
   android:layout_height="50dp"
   android:background="@color/colorPrimary">

<ImageView
     android:id="@+id/iv_back"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_centerVertical="true"
     android:layout_marginLeft="10dp"
     android:src="@drawable/new_img_back" />

<TextView
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_centerInParent="true"
     android:text="@string/app_name"
     android:textColor="@android:color/white"
     android:textSize="18sp" />

</RelativeLayout>

<com.yuqirong.tabsuspenddemo.view.MyScrollView
   android:id="@+id/mScrollView"
   android:layout_width="match_parent"
   android:layout_height="match_parent">

<LinearLayout
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="#cccccc"
     android:orientation="vertical">

<ImageView
       android:id="@+id/iv_pic"
       android:layout_width="match_parent"
       android:layout_height="180dp"
       android:scaleType="centerCrop"
       android:src="@drawable/ic_bg_personal_page" />

<include layout="@layout/tab_layout" />

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

<LinearLayout
       android:layout_width="match_parent"
       android:layout_height="90dp"
       android:layout_marginBottom="5dp"
       android:layout_marginLeft="15dp"
       android:layout_marginRight="15dp"
       android:layout_marginTop="15dp"
       android:background="@android:color/white"
       android:orientation="horizontal">

</LinearLayout>

</LinearLayout>
 </com.yuqirong.tabsuspenddemo.view.MyScrollView>
</LinearLayout>

Tab栏的布局,tab_layout.xml:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/ll_tab"
 android:layout_width="match_parent"
 android:layout_height="40dp"
 android:background="@color/colorPrimary"
 android:orientation="horizontal">

<TextView
   android:layout_width="0dp"
   android:layout_height="match_parent"
   android:layout_weight="1"
   android:gravity="center"
   android:text="分类"
   android:textColor="@android:color/white"
   android:textSize="18sp" />

<TextView
   android:layout_width="0dp"
   android:layout_height="match_parent"
   android:layout_weight="1"
   android:gravity="center"
   android:text="排序"
   android:textColor="@android:color/white"
   android:textSize="18sp" />

<TextView
   android:layout_width="0dp"
   android:layout_height="match_parent"
   android:layout_weight="1"
   android:gravity="center"
   android:text="筛选"
   android:textColor="@android:color/white"
   android:textSize="18sp" />

</LinearLayout>

上面布局中的很多空白LinearLayout主要是拉长ScrollView,效果图就是这样的:

Android实现App中导航Tab栏悬浮的功能

然后我们来看看onCreate(Bundle savedInstanceState):


@Override
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 getSupportActionBar().hide();
 setContentView(R.layout.activity_main);
 mScrollView = (MyScrollView) findViewById(R.id.mScrollView);
 mScrollView.setOnScrollListener(this);
 ll_tab = (LinearLayout) findViewById(R.id.ll_tab);
 windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
}

我们先在onCreate(Bundle savedInstanceState)中给ScrollView添加了滑动距离 * 以及得到了一个windowManager的对象。还有一点需要注意的是:我们调用了getSupportActionBar().hide();去掉了标题栏(MainActivity继承了AppCompatActivity)。这是因为标题栏的存在导致了在计算悬浮窗y轴的值时要额外加上标题栏的高度(当然你也可以保留标题栏,然后计算时再加上标题栏的高度^_^!)。

然后在onWindowFocusChanged(boolean hasFocus)得到Tab栏的高度、getTop()值等,以便下面备用。


@Override
public void onWindowFocusChanged(boolean hasFocus) {
 super.onWindowFocusChanged(hasFocus);
 if (hasFocus) {
   tabHeight = ll_tab.getHeight();
   tabTop = ll_tab.getTop();
   scrollTop = mScrollView.getTop();
 }
}

之后在滑动 * 的回调方法onScroll(int scrollY)中来控制显示还是隐藏悬浮窗。


@Override
public void onScroll(int scrollY) {
 Log.i(TAG, "scrollY = " + scrollY + ", tabTop = " + tabTop);
 if (scrollY > tabTop) {
// 如果没显示
   if (!isShowWindow) {
     showWindow();
   }
 } else {
// 如果显示了
   if (isShowWindow) {
     removeWindow();
   }
 }
}

上面的代码比较简单,不用我过多叙述了。下面是removeWindow() showWindow()两个方法:


// 显示window
private void removeWindow() {
 if (ll_tab_temp != null)
   windowManager.removeView(ll_tab_temp);
 isShowWindow = false;
}

// 移除window
private void showWindow() {
 if (ll_tab_temp == null) {
   ll_tab_temp = LayoutInflater.from(this).inflate(R.layout.tab_layout, null);
 }
 if (layoutParams == null) {
   layoutParams = new WindowManager.LayoutParams();
   layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; //悬浮窗的类型,一般设为2002,表示在所有应用程序之上,但在状态栏之下
   layoutParams.format = PixelFormat.RGBA_8888;
   layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
       | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; //悬浮窗的行为,比如说不可聚焦,非模态对话框等等
   layoutParams.gravity = Gravity.TOP; //悬浮窗的对齐方式
   layoutParams.width = WindowManager.LayoutParams.MATCH_PARENT;
   layoutParams.height = tabHeight;
   layoutParams.x = 0; //悬浮窗X的位置
   layoutParams.y = scrollTop; //悬浮窗Y的位置
 }
 windowManager.addView(ll_tab_temp, layoutParams);
 isShowWindow = true;
}

这两个方法也很简单,而且有注释,相信大家可以看懂。

最后,不要忘了在AndroidManifest.xml里申请显示悬浮窗的权限:


<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

到这里,整体的代码就这些了。一起来看看效果吧:

Android实现App中导航Tab栏悬浮的功能

值得注意的是:如果用这种方法来实现Tab栏悬浮功能有一个缺点,那就是如果该app没有被赋予显示悬浮窗的权限,那么该功能就变成鸡肋了。

总结

标签:android,悬浮,tab
0
投稿

猜你喜欢

  • Spring如何更简单的读取和存储对象

    2023-09-30 00:32:14
  • java编程之基于SpringBoot框架实现扫码登录

    2023-02-14 02:39:28
  • SpringBoot解决跨域请求拦截问题代码实例

    2021-07-18 12:08:54
  • 浅谈MyBatis3 DynamicSql风格语法使用指南

    2023-11-25 13:05:06
  • Java中Excel高效解析工具EasyExcel的实践

    2023-05-28 13:36:38
  • Java设计模式之状态模式State Pattern详解

    2023-11-07 07:55:01
  • java并发编程专题(六)----浅析(JUC)Semaphore

    2023-07-27 23:30:28
  • Java中的static关键字修饰属性和方法(推荐)

    2021-09-29 05:46:20
  • Swagger注解-@ApiModel和@ApiModelProperty的用法

    2023-02-05 23:57:48
  • JAVA多线程并发下的单例模式应用

    2022-09-15 01:27:31
  • C#用链式方法表达循环嵌套

    2023-04-14 06:54:23
  • Java使用Hutool实现AES、DES加密解密的方法

    2021-06-03 16:49:57
  • Java的类型擦除式泛型详解

    2022-01-02 11:59:00
  • 浅谈Spring Boot 开发REST接口最佳实践

    2021-10-08 12:24:35
  • 在WinForm中发送HTTP请求的实现方法

    2023-01-28 10:47:35
  • 以Java代码为例讲解设计模式中的简单工厂模式

    2023-02-09 15:14:17
  • Java之NIO基本简介

    2021-12-20 22:15:44
  • Netty分布式NioEventLoop任务队列执行源码分析

    2022-10-08 04:07:19
  • easyexcel读取excel合并单元格数据的操作代码

    2022-08-26 16:26:21
  • java.lang.ExceptionInInitializerError异常的解决方法

    2023-01-13 04:23:16
  • asp之家 软件编程 m.aspxhome.com