[Android] UI进阶笔记:从 Toolbar 到可折叠标题栏的完整实战

学习 Android 开发的过程中,UI 控件往往是最直观也最容易踩坑的部分。本文整理了我在学习《第一行代码》后的实践笔记,涵盖 Toolbar、自定义标题栏、菜单、Snackbar、CoordinatorLayout、可折叠标题栏、SwipeRefreshLayout 下拉刷新、FloatingActionButton 悬浮按钮 等常见控件的使用方法和心得体会。通过这些总结,希望能帮助你快速掌握 Android 界面开发的核心知识点,让界面更灵活、更具交互感eve~

Toolbar

Toolbar是什么?

  • Toolbar 是 Android 5.0)后引入的新控件,用来替代以前的 ActionBar,可以自由控制位置、样式
  • 因为是可自定义的,所以比 ActionBar 灵活得多

Toolbar 的常见功能

  1. 应用标题
    默认显示 App 名称,你可以改成自定义标题
  2. 导航按钮(返回键 / 菜单按钮)
    可以添加返回箭头、菜单按钮,或者换成你想要的图标
  3. 菜单
    可以在右上角加"搜索""更多"等按钮
  4. 完全自定义布局
    Toolbar 内部可以放 TextView、ImageView,甚至自定义控件

Toolbar的使用(配合菜单)

  • 可以直接在layout布局文件中使用:
Android 复制代码
<Toolbar
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:id = "@+id/toolbar"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme = "@style/ThemeOverlay.AppCompat.Dark"
    app:layout_constraintTop_toTopOf="parent"
    android:title="你好"
    >

</Toolbar>

以上代码中有两个较为陌生的属性:

  • android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"代表顶部导航栏的主题颜色

@style/ThemeOverlay.AppCompat.Dark.ActionBar代表白色字体图标;@style/ThemeOverlay.AppCompat.Light表示深色字体图标

  • app:popupTheme = "@style/ThemeOverlay.AppCompat.Dark" 表示菜单的主体颜色

@style/ThemeOverlay.AppCompat.Light→ 白色弹窗 @style/ThemeOverlay.AppCompat.Dark → 深色弹窗

  • app:navigationIcon 设置左上角的导航图标(常见是返回箭头)

菜单项这样来写:

Android 复制代码
   <item
       android:id="@+id/it1"
       android:icon="@drawable/ic_launcher_background"
       android:title="TODO"
       app:showAsAction = "always">

   </item>
<item
    android:id="@+id/it2"
    android:icon="@drawable/ic_launcher_foreground"
    android:title="TOD1"
    app:showAsAction = "ifRoom">

</item>
<item
    android:id="@+id/it3"
    android:title="TOD2"
    android:icon="@drawable/ic_launcher_foreground"
    app:showAsAction = "never">

</item>

app:showAsAction = "always" 代表表现的方式:

always代表一定要显示在顶部导航栏,否则不显示

ifRoom代表如果能显示显示,不能显示就去菜单项

never一定在菜单项

最后把菜单项膨胀到视图,一定要使用这个方法,因为有菜单时,系统会回调这个方法;

Android 复制代码
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.toolbai,menu);
    return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getItemId() == R.id.action_search) {
        Toast.makeText(this, "点击了搜索", Toast.LENGTH_SHORT).show();
        return true;
    }
    return super.onOptionsItemSelected(item);
}

设置toolbar

Android 复制代码
Toolbar toolbars = (Toolbar)findViewById(R.id.toolbar);
setSupportActionBar(toolbars);

设置导航按钮(返回箭头)

Android 复制代码
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbars.setNavigationOnClickListener(v -> finish());

注意:toolbar最好使用androidx

Android 复制代码
androidx.appcompat.widget.Toolbar

使用Androidx的toolbar时需要添加依赖,依赖如下:

Android 复制代码
implementation 'androidx.appcompat:appcompat:1.6.1'

当然我们也可以自定义toolbar,在toolbar中自定义控件:

Android 复制代码
Toolbar toolbar = findViewById(R.id.custom_toolbar);
setSupportActionBar(toolbar);
// 去掉系统默认标题,使用我们自己的 TextView
getSupportActionBar().setDisplayShowTitleEnabled(false);

getSupportActionBar().setDisplayShowTitleEnabled(false);核心就是设置后setSupportActionBar的这一句代码,我们就可以使用自定义控件了,那么具体怎么自定义,那就看你想要什么样子的效果啦;

不过需要注意一点,这里只是去掉了默认的标题,所以系统默认的标题不显示了,但是我们仍然可以使用其他方法,比如设置返回图标;

好了,Toolbar的简单学习先到这里;

FloatingActionButton

这是悬浮按钮 ,我们可以做点击事件

在xml文件中简单使用如下

Android 复制代码
<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|right"
    android:layout_margin="20dp"
    android:id = "@+id/fa"
    android:elevation="2dp"
    android:src = "@drawable/ic_launcher_foreground"

/>

属性解释:

android:elevation="2dp" 数值越大,阴影面积大,但浅,反之则相反;

android:src = "@drawable/ic_launcher_foreground"可用来添加图片

Snackbar

一个功能类似toast提示框,与toast不同的是,可以和用户交互

Android 复制代码
floatingActionButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Snackbar.make(view,"嘿嘿",Snackbar.LENGTH_LONG).setAction("确定", new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this,"雪雪学安卓",Toast.LENGTH_SHORT).show();
            }
        }).show();
    }
});

Snackbar.make(view,"嘿嘿",Snackbar.LENGTH_LONG);

  • make方法是确认提示主体 ,第一个参数是界面任意 一个view,snackbar会自动选择最上层那一个,第二个参数是提示语

  • setAction方法 通过setaction方法和用户交互 ,第一个参数是按钮效果 ,第二个参数做监听

最后别忘记show()!

CoordinatorLayout布局

这个布局和帧布局差不多

但是它可以监听所有 的子控件,从而做出最佳响应:比如悬浮按钮和提示框重合问题

需要注意的是:

那前提得是子控件,所以提示框传入的view参数得是coordinatorlayout的子控件了;

glide依赖如下

Android 复制代码
    implementation 'com.github.bumptech.glide:glide:4.16.0'

Recycleview进阶版

可能照片资源过大,所以这个时候就需要它了;

依赖如下:

Android 复制代码
implementation 'com.github.bumptech.glide:glide:4.16.0'

Glide.with(mcontext).load(fruit.getImageid()).into(holder.imageView);

第一个参数是context ,第二个是把这个id加载到第三个参数的布局中

Android 复制代码
GridLayoutManager layoutManager = new GridLayoutManager(this,2);

代表两列

Android 复制代码
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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">
        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:id = "@+id/toolbar"
            android:theme="@style/Widget.AppCompat.Light.ActionBar"
            app:popupTheme = "@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways|snap"
            app:layout_constraintTop_toTopOf="parent"
            android:title="你好"
            >
        </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        android:id="@+id/recy">

    </androidx.recyclerview.widget.RecyclerView>

陌生属性介绍:

  • com.google.android.material.appbar.AppBarLayout 这个布局为了顶部导航栏的显示

  • app:layout_behavior="@string/appbar_scrolling_view_behavior" 为了顶部导航栏的显示,否则可能遮挡顶部导航栏;

  • app:layout_scrollFlags="scroll|enterAlways|snap"

scroll 作用:视图会随着内容滚动而一起滚动(向上滑时隐藏,向下滑时显示

enterAlways 作用: 向下滚动时立即显示视图(不需要滚动到顶部)

snap 作用: 滚动停止时自动"吸附"到最近的边界(要么完全显示,要么完全隐藏, 提供更流畅的用户体验

exitUntilCollapsed

作用:

  • 视图会滚动退出,但不会完全消失,而是停留在折叠状态
  • 必须scroll 标志一起使用
  • 需要定义 minHeight 属性指定折叠后的高度

我们通常是scroll和exitUntilCollapsed搭配使用!

SwipeRefreshLayout下拉刷新

依赖:

Android 复制代码
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'

xml文件:用法包在recyview外面表示刷新

implementation 复制代码
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:layout_width="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    android:id = "@+id/swip"
    android:layout_height="match_parent">
    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recy">

    </androidx.recyclerview.widget.RecyclerView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

在mainactivity

我把过程中难以理解的代码都标注出来啦

implementation 复制代码
SwipeRefreshLayout swipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swip);
swipeRefreshLayout.setColorSchemeColors(R.color.black);//刷新的颜色
swipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
//每次刷新都会回调
    @Override
    public void onRefresh() {
    //经常得到数据之后,开始刷新,所以要在子线程中
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                //回到主线程中
                 runOnUiThread(new Runnable() {
                     @Override
                     public void run() {
                     //适配器刷新Notify
                         fruitadapots.notifyDataSetChanged();
                         //表示刷新事件结束,隐藏刷新进度条
                         swipeRefreshLayout.setRefreshing(false);
                     }
                 });

            }
        }).start();
    }
});

可折叠式表示栏

CoordinatorLayout

这是最外层的布局

然后你需要把你的用于折叠的照片,还有顶部导航栏,都设置在appbarlayout布局中

Android 复制代码
<com.google.android.material.appbar.AppBarLayout
    android:layout_height="250dp"
    android:layout_width="match_parent"
    android:id = "@+id/appbar">
    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id = "@+id/coll"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        app:contentScrim="?attr/colorPrimary"
        app:layout_scrollFlags="snap|scroll|exitUntilCollapsed">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id = "@+id/iv"
            app:layout_collapseMode="parallax"
            android:scaleType="centerCrop"
            >

        </ImageView>
        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:id = "@+id/toolbar"
            app:layout_collapseMode="pin">

        </androidx.appcompat.widget.Toolbar>
    </com.google.android.material.appbar.CollapsingToolbarLayout>


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

定义在CollapsingToolbarLayout

  • android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" 代表设置一个主题

  • app:contentScrim="?attr/colorPrimary"代表这个布局在趋于折叠和折叠后的背景色

  • app:layout_scrollFlags="snap|scroll|exitUntilCollapsed"是appbarlayout中的属性

app:layout_collapseMode="parallax"表示折叠模式

有三种折叠模式:

Pin代表在折叠时永不消失,这里代表顶部导航栏,在折叠会回固定在顶部,通常和toolbar一起联合使用;

parallax模式(视差模式) 效果:控件以较慢速度 滚动,产生景深效果,我们还可以设置它的滚动的速度,更有感觉。

滚动的速度通过此来控制,数值越小,速度越慢: app:layout_collapseParallaxMultiplier="0.7"

默认模式(无模式) 效果:控件会随滚动完全消失,一般不设置,无折叠效果。

中间内容:经常是recycleview等等

Android 复制代码
<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <androidx.cardview.widget.CardView
            android:layout_width="match_parent"
            android:id = "@+id/card"
            app:cardCornerRadius="4dp"
            android:layout_margin="10dp"
            android:layout_height="wrap_content">
            <TextView
                android:layout_width="match_parent"
                android:id = "@+id/tv"
                android:layout_height="wrap_content">

            </TextView>
        </androidx.cardview.widget.CardView>
    </LinearLayout>

</androidx.core.widget.NestedScrollView>

app:layout_behavior="@string/appbar_scrolling_view_behavior" 这个属性搭配折叠效果;

NestedScrollView只能有一个直接子项布局

体会

编者对于在运用折叠式标题栏时有了一些新的体会

  1. 当你在某控件中设置parallax,即使折叠后仍然显示当前折叠时的背景,它不会因为折叠就直接消失显示pin模式下的控件,假如parallax设置的是背景图,那么背景图会和pin模式下的视图重叠,直接你看不到是因为通常toobar设置的是pin,toolbar的会挡住背景图,当你尝试把toolbar设置为透明时,你会发现有重合的问题qvq;
  2. 折叠后的高度由谁决定? AI中会解释道:由toolbar的高度决定,但你仔细看,你就会发现是由使用pin模式的控件 决定的,因为toolbar设置了pin,所以AI才会这样解释,当我们toolbar中的设置为100dp,那么折叠后的高度就是100dp了;此时又发现一个属性minheigh(控制 CollapsingToolbarLayout的最小可见高度),它也会影响高度,当它的高度大于PIN模式下控件的高度时,那么此时折叠后的高度就是minheight了,所以如果是minHeight比toolbar的高度要高,最后的结果就是上面是toolbar,折叠后仍然留有一部分高度是minheight的剩余高度;
  3. 可折叠模式写在coll布局的直接子view中;
  4. 当有很多空间都设置了pin模式,按照在xml文件中的排布在顶部依次显示;
  5. 可折叠式标题栏的核心:

最外层是coor的一个布局

中间套 appbarlayout负责响应滑动:android:fitsSystemWindows="true"这里这个属性true代表toolbar在状态栏下方,避免系统的窗口区域和布局重叠

里面是coll的一个布局:里面写两个重要属性:app:layout_scrollFlags,控制滚动的效果,app:contentScrim 折叠后显示的背景色(不写会出现透明/白色突兀问题);

在未折叠的布局中写属性控制折叠后的效果;

在内容区例如recycleview或者scroll中写app:layout_behavior="@string/appbar_scrolling_view_behavior"不然滑动不会带动 AppBar 折叠;

希望编者的理解对你有帮助哦!

悬浮按钮升级版

Android 复制代码
<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="16dp"
    app:layout_anchor="@id/appbar"
    app:layout_anchorGravity="bottom|end"
    >

</com.google.android.material.floatingactionbutton.FloatingActionButton>

app:layout_anchor="@id/appbar" 锚定谁

app:layout_anchorGravity="bottom|end" 锚定谁的哪里

anchor锚点

这么设置就会出现在标题栏的区域内

另外:

collapsingToolbarLayout.setTitle("i like");

这里也可以设置折叠后导航栏的标题搭配顶部导航栏的使用

本次分享到这里结束!

相关推荐
安卓理事人4 小时前
安卓LinkedBlockingQueue消息队列
android
万能的小裴同学5 小时前
Android M3U8视频播放器
android·音视频
q***57746 小时前
MySql的慢查询(慢日志)
android·mysql·adb
JavaNoober6 小时前
Android 前台服务 "Bad Notification" 崩溃机制分析文档
android
城东米粉儿7 小时前
关于ObjectAnimator
android
zhangphil8 小时前
Android渲染线程Render Thread的RenderNode与DisplayList,引用Bitmap及Open GL纹理上传GPU
android
火柴就是我9 小时前
从头写一个自己的app
android·前端·flutter
lichong95110 小时前
XLog debug 开启打印日志,release 关闭打印日志
android·java·前端
用户693717500138410 小时前
14.Kotlin 类:类的形态(一):抽象类 (Abstract Class)
android·后端·kotlin
火柴就是我11 小时前
NekoBoxForAndroid 编译libcore.aar
android