一篇文章了解CoordinatorLayout和toolbar、悬浮按钮各种联动

前言

如果你的业务涉及到列表上下滑动隐藏显示toolbar(标题栏)或者是你的悬浮按钮根据列表的滑动做上下隐藏,左右隐藏。(若是产品提出仿某b站上下滑动隐藏消失,仿某宝购物车移动上下滑动使其左右隐藏显示)那么恭喜你,直接发动 cc + cv 技能 完美完成需求,大家可以先看下下方实现的效果样式。

图片名称

需要看代码的话直接点下方链接

github代码直通车

toolbar根据滑动上下隐藏实现

      <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:elevation="0dp">

            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@color/white"
                android:contentInsetStart="0dp"
                app:contentInsetStart="0dp"
                app:layout_scrollFlags="scroll|enterAlways|snap"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
                  //...
            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.AppBarLayout>


layout_scrollFlags

这边实现主要是根据 layout_scrollFlags 这个属性判断的,一共有5种属性

  • scroll
    Child View 伴随着滚动事件而滚出或滚进屏幕。注意两点:第一点,如果使用了其他值,必定要使用这个值才能起作用;第二点:如果在这个child View前面的任何其他Child View没有设置这个值,那么这个Child View的设置将失去作用。

  • enterAlways
    它修改返回的视图,使其最初只滚动回它的折叠高度。一旦滚动视图到达滚动范围的末尾,该视图的其余部分将被滚动到视图中。折叠高度由视图的最小高度定义。

  • enterAlwaysCollapsed
    退出(滚屏)时,视图将被滚动,直到它被“折叠”。

  • snap
    在滚动结束时,如果视图只有部分可见,那么它将被抓取并滚动到最近的边缘。就是停止滚动时要么toolbar完全显示要么完全消失两种状态

  • exitUntilCollapsed
    向上滚动时,toolbar向上滚动退出直至最小高度,然后 开始滚动。就是不会完全退出屏幕的意思。

悬浮按钮根据滑动消失隐藏

这里主要用到 CoordinatorLayout.Behavior<View> 。我们根据监听滑动距离来做相应的处理,实现也很简单。

package com.hugh.basis.coordinatorLayoutPage.behavior;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;



import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import androidx.core.view.ViewPropertyAnimatorListener;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;

/**
 * Created by chenyw on 2020/9/2.
 */
public class ViewRightInOutBehavior extends CoordinatorLayout.Behavior<View> {

    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();

    private boolean mAnimatingOut = false;


    public ViewRightInOutBehavior() {
    }

    public ViewRightInOutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
        //需要垂直的滑动
        return axes == ViewCompat.SCROLL_AXIS_VERTICAL ||
                super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type);
    }

    @Override
    public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);
        if (dyConsumed > 0 && !mAnimatingOut) {
            //向上滑动
            animateOut(child);
        } else if (dyConsumed < 0) {
            //向下滑动
            animateIn(child);
        }
    }

    private void animateOut(final View button) {
        ViewCompat.animate(button)
                .translationX(button.getWidth() + getMarginBottom(button))
                .setInterpolator(INTERPOLATOR)
                .withLayer()
                .setListener(new ViewPropertyAnimatorListener() {
                    public void onAnimationStart(View view) {
                        mAnimatingOut = true;
                    }

                    public void onAnimationCancel(View view) {
                        mAnimatingOut = false;
                    }

                    public void onAnimationEnd(View view) {
                        mAnimatingOut = false;
                    }
                })
                .start();
    }

    private void animateIn(View button) {
        ViewCompat.animate(button).translationX(0).setInterpolator(INTERPOLATOR).withLayer().setListener(null).start();
    }

    private int getMarginBottom(View v) {
        final ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
        if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
            return ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
        }
        return 0;
    }

}

在xml中使用上面的 behavior

     <ImageView
            android:id="@+id/float_dub"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="end|bottom"
            android:layout_marginEnd="20dp"
            android:layout_marginBottom="20dp"
            android:src="@android:drawable/ic_dialog_info"
            app:layout_behavior=".coordinatorLayoutPage.behavior.ViewBottomInOutBehavior"
            tools:visibility="visible" />
            

Behavior的嵌套NestedScrolling触摸事件

onStartNestedScroll() onNestedScrollAccepted() onStopNestedScroll() onNestedScroll() onNestedPreScroll() onNestedFling() onNestedPreFling()

这上述功能中主要实现 onNestedScroll方法 ,提供给我们相应的滑动距离给予我们做业务判断

布局文件

xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white">

    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:id="@+id/layout_cooRoot"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <com.google.android.material.appbar.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:elevation="0dp">

            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                android:background="@color/white"
                android:contentInsetStart="0dp"
                app:contentInsetStart="0dp"
                app:layout_scrollFlags="scroll|enterAlways|snap"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

                <androidx.constraintlayout.widget.ConstraintLayout
                    android:id="@+id/actionBar"
                    android:layout_width="match_parent"
                    android:layout_height="44dp"
                    android:layout_below="@+id/view_hold"
                    android:background="@color/white">


                    <LinearLayout
                        android:id="@+id/layout_search"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginLeft="15dp"
                        android:layout_marginRight="15dp"
                        android:background="@drawable/oval_c8"
                        android:gravity="center"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintHorizontal_weight="1"
                        app:layout_constraintRight_toLeftOf="@+id/iv_history"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent">

                        <TextView
                            android:id="@+id/tv_search"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:drawableLeft="@drawable/home_icon_searchnew"
                            android:drawablePadding="4dp"
                            android:gravity="center"
                            android:paddingTop="7dp"
                            android:paddingBottom="7dp"
                            android:text="哈哈哈哈哈搜索"
                            android:textColor="@color/c5"
                            android:textSize="14sp" />
                    </LinearLayout>


                    <ImageView
                        android:id="@+id/iv_history"
                        android:layout_width="26dp"
                        android:layout_height="26dp"
                        android:layout_centerInParent="true"
                        android:layout_marginRight="13dp"
                        android:scaleType="center"
                        android:src="@color/yellow"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintRight_toLeftOf="@+id/iv_message"
                        app:layout_constraintTop_toTopOf="parent" />

                    <ImageView
                        android:id="@+id/iv_message"
                        android:layout_width="26dp"
                        android:layout_height="26dp"
                        android:layout_centerInParent="true"
                        android:layout_marginRight="13dp"
                        android:scaleType="center"
                        android:src="@color/yellow"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />


                </androidx.constraintlayout.widget.ConstraintLayout>
            </androidx.appcompat.widget.Toolbar>

        </com.google.android.material.appbar.AppBarLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:gravity="center_horizontal"
            android:orientation="vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <net.lucode.hackware.magicindicator.MagicIndicator
                android:id="@+id/magic_indicator1"
                android:layout_width="match_parent"
                android:layout_height="44dp"
                android:background="@android:color/white" />

            <androidx.viewpager.widget.ViewPager
                android:id="@+id/viewPager"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_below="@+id/magic_indicator1"
                android:flipInterval="30"
                android:persistentDrawingCache="animation" />
        </LinearLayout>

        <ImageView
            android:id="@+id/img_float_ad"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_gravity="center|end"
            android:src="@android:drawable/ic_dialog_email"
            app:layout_behavior=".coordinatorLayoutPage.behavior.ViewRightInOutBehavior"
            tools:background="@color/c6"
            tools:visibility="visible" />

        <ImageView
            android:id="@+id/float_dub"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_gravity="end|bottom"
            android:layout_marginEnd="20dp"
            android:layout_marginBottom="20dp"
            android:src="@android:drawable/ic_dialog_info"
            app:layout_behavior=".coordinatorLayoutPage.behavior.ViewBottomInOutBehavior"
            tools:visibility="visible" />
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
</FrameLayout>

需要上述整体实现逻辑的话可以直接点 github代码直通车

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Qt工具栏是Qt界面设计中常用的一种控件,可以用来组织和展示一系列操作命令、按钮等。Qt工具栏提供了一些常用的悬浮功能,实现起来也十分简单。 Qt工具栏的悬浮功能可以通过设置工具栏的属性来实现,可以设置工具栏的可浮动性,即setMovable()函数,以及工具栏是否占用独立行,即setFloatable()函数。其中,setMovable()函数可以使得工具栏变得可浮动,供用户随意拖动,并根据拖动的位置决定应该将工具栏添加到哪个区域。setFloatable()函数则可以使得工具栏拥有浮动的能力,在主窗口内自由浮动移动,并且可以随时隐藏显示。如果需要在工具栏悬浮时改变工具栏的外观,可以通过setOrientation()函数设置工具栏的方向。 除了Qt自带的悬浮功能,还可以通过自定义实现工具栏的悬浮功能。自定义悬浮功能需要重写工具栏的鼠标事件,并在鼠标移动过程中实时判断工具栏应该处于的位置,并根据鼠标位置和工具栏的大小重新计算坐标。当鼠标释放时,如果判断鼠标在工具栏周围,则将工具栏添加到该位置;否则将工具栏添加到最近的工具栏区域。 总之,Qt工具栏的悬浮功能可以帮助用户更加方便地使用操作命令,并且可以根据实际需要自定义悬浮功能。 ### 回答2: Qt工具栏的悬浮是指鼠标指针经过工具栏时该工具栏会自动弹出来,并可以在鼠标离开工具栏后自动隐藏的功能。这个功能通过Qt提供的QToolBar类和setFloatable()方法来实现。当setFloatable()方法设置为true时,工具栏可以悬浮;当设置为false时,工具栏不悬浮。同时,Qt还提供了setMovable()方法来控制工具栏是否可以移动。通过设置setMovable()方法为true,工具栏就可以被拖拽来改变它的位置。 另外,Qt还提供了isFloating()方法,用于判断工具栏是否正在悬浮。需要注意的是,当isVisible()和isFloating()方法都返回true时,表示工具栏正在显示且正在悬浮。 如果想要控制工具栏的悬浮状态,可以使用setAllowedAreas()方法或QMainWindow类中的setDockOptions()方法来设置工具栏可以停靠的区域。还可以利用QDockWidget类来将工具栏嵌入到一个可停靠的窗口中,从而可以更好地控制工具栏的悬浮效果。 综上所述,Qt工具栏悬浮是一种非常实用的功能,可以大大提升用户的使用体验。开发者可以根据实际需求来使用Qt提供的相关方法和类来实现工具栏的悬浮效果。 ### 回答3: qt 工具栏(Toolbar)提供了一种在应用程序主窗口中快速访问常用操作的方式。其中,悬浮工具栏(QToolBar)是一种特殊的工具栏,可以随着鼠标的移动而在主窗口中浮动显示悬浮工具栏通常包含一些常用的工具按钮,比如剪切、复制、粘贴、撤销、重做等常用操作。它们可以根据应用程序的需求进行自定义,方便用户快速地完成操作。 在使用 Qt 构建应用程序时,开发者可以通过设置一些属性和信号槽来实现悬浮工具栏的显示隐藏。例如,可以使用 setFloatable() 方法设置悬浮工具栏是否可以浮动,并使用 setMovable() 方法来指定是否可以移动悬浮工具栏。此外,可以通过工具栏中按钮的 clicked() 信号来控制悬浮工具栏的显示隐藏。 总之,悬浮工具栏是一种非常实用的界面设计,能够为用户提供快速的操作方式,同时又不占用主窗口过多的空间。在应用程序开发中,合理使用悬浮工具栏,可以提升用户的操作体验,增强应用程序的易用性和便捷性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值