Android开发的UI设计——Material Design

news2024/11/15 2:21:55

前言

Material Design 是用于指导用户在各种平台和设备上进行视觉、动作和互动设计的全面指南。如需在您的 Android 应用中使用 Material Design,请遵循 Material Design 规范中定义的准则,并使用 Material Design 支持库中提供的新组件和样式。

正篇

安卓中的Material Design

作为Google旗下的一员——安卓,则是将其一些最具代表性一些控件和效果封装在_Material库_,这就让我们开发者可以在不了解Material Design的情况下,也很容易将自己的应用Material化,当然现在在AndroidX库中的一些组件也可以实现一些Material Design的效果。

BottomSheetDialogFragment组件

介绍

这个组件在Material Design中分属Bottom Sheets

编辑

BottomSheetDialogFragment 继承自 AppCompatDialogFragment,官方解释为模态底部表,是 DialogFragment 的一个版本,它使用的是 BottomSheetDialog,而不是浮动对话框。

优势

1、拥有自己的生命周期;
2、可对整个页面进行折叠、展开和销毁;
3、可灵活使用自定义样式。

使用方法

implementation 'com.google.android.material:material:1.7.0'

添加好后Sync Gradle成功后,我们就可以在项目中添加BottomSheetDialogFragment了,很简单,和正常写继承DialogFragment的Dialog一样,因为在上述中我们看到了其继承关系,BottomSheetDialogFragment是继承自AppCompatDialogFragment,而
AppCompatDialogFragment又是继承自DialogFragment。如此一来,由于BottomSheetDialogFragment是DialogFragment的子类,故它具有DialogFragment的所有特性。

实现需求

Dialog部分的实现代码

class DialogMore : BottomSheetDialogFragment() {
    private var height : Int = 0

    fun newInstance(): DialogMore {
        return DialogMore()
    }

    fun setDialogHeight(height: Int): DialogMore {
        this.height = height
        return this
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(STYLE_NORMAL, R.style.StyleBottomSheetDialogBg)
    }

    override fun onStart() {
        super.onStart()
        //拿到系统的 bottom_sheet
        val bottomSheetDialog = (dialog as BottomSheetDialog?)!!
        val view =
            bottomSheetDialog.delegate.findViewById<FrameLayout>(com.google.android.material.R.id.design\_bottom\_sheet)!!
        val behavior = BottomSheetBehavior.from(view)
        //设置弹出高度
        behavior.peekHeight = height
        view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
        behavior.isHideable = false
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val dialog = super.onCreateDialog(savedInstanceState)
        val view = LayoutInflater.from(context).inflate(R.layout.layout\_item\_dialog_more, null)
        dialog.setContentView(view)
        view.vDownClose.setOnClickListener {
            dismiss()
        }
        return dialog
    }

}

可以看到,这部分实现代码和我们平时写底部弹窗方法差不多,不过我们在onStar()方法可以使用BottomSheetBehavior去控制弹窗本身的行为,比如高度控制和一些弹窗的属性设置

在onCreateDialog方法中我们把弹窗布局加进去,使用setContentView()方法获取到布局,一定要写该方法,不然我们在获取BottomSheetBehavior的时候* val behavior = BottomSheetBehavior.from(view)*这句会报空

而我们的弹窗需要顶部圆角,且去除背景阴影,所以增加了样式:

<!--实现BottomSheetDialog圆角效果 且无背景阴影-->
<style name="StyleBottomSheetDialogBg" parent="Theme.Design.Light.BottomSheetDialog">
    <item name="bottomSheetStyle">@style/StyleBottomSheetStyleWrapper</item>
    <item name="android:backgroundDimEnabled">false</item>
</style>
<style name="StyleBottomSheetStyleWrapper" parent="Widget.Design.BottomSheet.Modal">
    <item name="android:background">@android:color/transparent</item>
</style>

该地方样式在Dialog实现代码处调用,在onCreate方法中使用setStyle()方法。


此外,我们还需要在自己的布局中添加圆角:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners
        android:topLeftRadius="15dp"
        android:topRightRadius="15dp" />
    <solid android:color="@color/white" />
</shape>

样式可以添加在我们定义的弹窗布局最外层布局

Dialog样例布局如下

<?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="wrap\_content"
    android:background="@drawable/shape\_sheet\_dialog_bg"
    android:orientation="vertical">
    <LinearLayout
        android:layout\_width="match\_parent"
        android:layout\_height="wrap\_content"
        android:layout_gravity="center"
        android:paddingTop="10dp"
        android:paddingStart="16dp"
        android:paddingEnd="16dp"
        android:gravity="center"
        android:orientation="horizontal">
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/vDownClose"
            android:layout_width="48dp"
            android:layout\_height="wrap\_content"
            android:layout_marginStart="16dp"
            android:layout_gravity="center"
            android:src="@drawable/vector\_invite\_comment_close" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/vTitle"
            android:layout\_width="match\_parent"
            android:layout\_height="wrap\_content"
            android:gravity="center"
            android:text="More Content"
            android:textColor="@color/black"
            android:textSize="16sp"
            android:textStyle="bold" />

        <androidx.appcompat.widget.AppCompatTextView
            android:id="@+id/vPositionEdit"
            android:layout_width="48dp"
            android:layout\_height="wrap\_content"
            android:layout_marginEnd="16dp"
            android:text=""
            android:textColor="@color/black"
            android:textSize="16sp" />

    </LinearLayout>
    <androidx.core.widget.NestedScrollView
        android:id="@+id/vNsPosition"
        android:layout\_width="match\_parent"
        android:layout\_height="match\_parent">

        <LinearLayout
            android:layout\_width="match\_parent"
            android:layout\_height="wrap\_content"
            android:orientation="vertical">

            <LinearLayout
                android:id="@+id/llPtz"
                android:layout\_width="match\_parent"
                android:layout_height="8dp"
                android:gravity="center"
                android:orientation="horizontal">
            </LinearLayout>
            <LinearLayout
                android:id="@+id/vLlPosition"
                android:layout\_width="match\_parent"
                android:layout\_height="match\_parent"
                android:orientation="vertical">
               <androidx.appcompat.widget.AppCompatImageView
                   android:layout\_width="match\_parent"
                   android:layout_height="300dp"
                   android:src="@mipmap/ic\_more\_content"
                   android:scaleType="fitCenter"/>

                <androidx.appcompat.widget.AppCompatTextView
                    android:layout\_width="match\_parent"
                    android:layout\_height="wrap\_content"
                    android:layout_marginTop="20dp"
                    android:layout_marginStart="16dp"
                    android:layout_marginEnd="16dp"
                    android:text="1.可以弹出弹窗,且弹窗可以继续拉到顶部。"
                    android:textSize="14dp"
                    android:textColor="#FF666666"/>
                <androidx.appcompat.widget.AppCompatTextView
                    android:layout\_width="match\_parent"
                    android:layout\_height="wrap\_content"
                    android:layout_marginTop="5dp"
                    android:layout_marginStart="16dp"
                    android:layout_marginEnd="16dp"
                    android:text="2.禁止下拉关闭弹窗,使下滑到固定位置后不会再动,关闭弹窗使用关闭按钮。"
                    android:textSize="14sp"
                    android:textColor="#FF666666"/>
            </LinearLayout>
            <LinearLayout
                android:id="@+id/vLlNoPosition"
                android:layout\_width="match\_parent"
                android:layout_height="277dp"
                android:layout_gravity="center"
                android:gravity="center"
                android:orientation="vertical"
                android:visibility="gone">
                <androidx.appcompat.widget.AppCompatTextView
                    android:id="@+id/vNoPositionText"
                    android:layout\_width="match\_parent"
                    android:layout\_height="match\_parent"
                    android:layout_gravity="center"
                    android:gravity="center"
                    android:text="无更多内容"
                    android:textSize="14sp"
                    android:textColor="#FF666666"/>
            </LinearLayout>

        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

</LinearLayout>

如果怕弹窗内部与外面的触控效果产生冲突,最简单的就是使用NestedScrollView控件,而不是普通的ScrollView布局

Activity的布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    tools:context=".MainActivity"
    android:orientation="vertical">
    <LinearLayout
        android:layout\_width="match\_parent"
        android:layout_height="56dp"
        android:orientation="horizontal">
        <LinearLayout
            android:layout_width="56dp"
            android:layout_height="56dp"
            android:orientation="horizontal"
            android:gravity="center">
            <androidx.appcompat.widget.AppCompatImageView
                android:layout_width="16dp"
                android:layout\_height="match\_parent"
                android:src="@drawable/vector\_arrow\_back"
                android:scaleType="fitCenter"/>
        </LinearLayout>
        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="horizontal">

            <androidx.appcompat.widget.AppCompatTextView
                android:layout\_width="wrap\_content"
                android:layout\_height="wrap\_content"
                android:textStyle="bold"
                android:text="弹窗样例"
                android:textColor="@color/black"
                android:textSize="16sp"
                app:autoSizeMaxTextSize="16sp"
                app:autoSizeMinTextSize="8dp"
                app:autoSizeTextType="uniform"
                android:maxLines="1"/>
        </LinearLayout>

        <LinearLayout
            android:layout_width="56dp"
            android:layout_height="56dp" />

    </LinearLayout>
    <androidx.appcompat.widget.AppCompatImageView
        android:layout\_width="wrap\_content"
        android:layout\_height="wrap\_content"
        android:src="@mipmap/ic\_play\_demo"
        android:scaleType="center"/>
    <LinearLayout
        android:layout\_width="match\_parent"
        android:layout_height="56dp"
        android:orientation="horizontal">
        <androidx.appcompat.widget.AppCompatImageView
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:src="@mipmap/ic\_top\_up"
            android:scaleType= "fitCenter"/>
        <androidx.appcompat.widget.AppCompatImageView
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:src="@mipmap/ic_transfer"
            android:scaleType= "fitCenter"/>
        <androidx.appcompat.widget.AppCompatImageView
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:src="@mipmap/ic_withdraw"
            android:scaleType= "fitCenter"/>
        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/vMore"
            android:layout_width="0dp"
            android:layout_height="56dp"
            android:layout_weight="1"
            android:src="@mipmap/ic_more"
            android:scaleType= "fitCenter"/>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/vllSize"
        android:layout\_width="match\_parent"
        android:layout\_height="match\_parent"
        android:background="@color/white"
        android:orientation="vertical"/>



</LinearLayout>

还有在Activity实现调用的代码

class MainActivity : AppCompatActivity() {

    private var dialogHeight : Int = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        // 获取dialog的高度

        dialogHeight = vllSize.measuredHeight
        // 获取dialog的高度
        Log.d( "MainActivity" ,"height = $dialogHeight")
    }

    override fun onResume() {
        super.onResume()

        vMore.setOnClickListener {
            val dialog  = DialogMore().newInstance()
                .setDialogHeight(dialogHeight)
            val ft: FragmentTransaction =
                supportFragmentManager.beginTransaction()
            ft.setTransition(FragmentTransaction.TRANSIT\_FRAGMENT\_FADE)
            dialog.show(ft, "DialogMore")
        }
    }
}

通过测量vllSize控件(剩余底部)的高度,我们可以将弹窗第一次弹窗的高度设置到这,当然高度可以由你任意设置,

在Dialog实现代码中:

override fun onStart() {
    super.onStart()
    //拿到系统的 bottom_sheet
    val bottomSheetDialog = (dialog as BottomSheetDialog?)!!
    val view =
        bottomSheetDialog.delegate.findViewById<FrameLayout>(com.google.android.material.R.id.design\_bottom\_sheet)!!
    val behavior = BottomSheetBehavior.from(view)
    //设置弹出高度
    behavior.peekHeight = height
    view.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
    behavior.isHideable = false
}

view.layoutParams.height我们设置了第二次可把弹窗拉动到整个屏幕上

本文中实现的弹窗禁止了相信滑动关闭弹窗,所以不会滑到底部,代码是Dialog实现中的属性控制,不写默认为true向下滑动关闭弹窗,false表示禁止该方式关闭弹窗:

behavior.isHideable = false

最终效果:


作者:茹迦怡
原文地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/60047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【软件安装】Ubuntu18.04及20.04中安装omnet++

注意&#xff1a;安装omnet首先看官方安装指导&#xff0c;不要直接百度。 omnet6.0.1官方安装指导omnet6.0只能在Ubuntu20.04及之后的版本使用&#xff0c;因为glibc版本不适配。 Ubuntu18.04安装omnet5.6.2 安装必要支持 更新apt-get $ sudo apt-get update安装依赖软件 $ s…

2022年四川省职业院校技能大赛网络搭建与应用赛项

2022年四川省职业院校技能大赛 网络搭建与应用赛项 &#xff08;一&#xff09; 技能要求 &#xff08;总分1000分&#xff09; 网络搭建与应用赛项执委会及专家组 2022年06月 竞赛说明 一、竞赛内容分布 “网络搭建与应用”竞赛共分三个部分&#xff0c;其中&#xff1a; 第一…

3个常用的损失函数

1. L2 loss &#xff08;均方损失&#xff09; 除以2就是可以在求导时2和1/2可以相乘抵消。 蓝色的曲线表示&#xff1a;y0时&#xff0c;变化预测值y’的函数。 绿色曲线表示&#xff1a;似然函数。e^-l。 是一个高斯分布。 橙色的线&#xff1a;表示损失函数的梯度 可以看到…

记录Windows下mysql更改my.ini文件中datadir路径后启动不起来的问题

1.mysql默认安装到了C盘&#xff0c;想将数据库存储路径改到别的盘下 将Data文件夹和日志复制到H盘 找到mysl服务&#xff0c;右键停止服务 更改my.ini文件中的路径 保存然后启动发现启动不起来 猜测原因1&#xff1a;文件夹没有权限 将文件夹权限给到所有的用户 右击 ”…

[附源码]Python计算机毕业设计Django青栞系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Linux的进程创建

在Linux下面&#xff0c;对二进制程序有着严格的格式要求&#xff0c;这就是ELF&#xff0c;这个格式可以根据编译的结果不同&#xff0c;分为不同的格式。 ELF的三种类型 一&#xff1a;可重定位文件 在编译的时候&#xff0c;先做预处理工作&#xff0c;例如将头文件嵌入到…

VueX简单又详细的解读,看了就会用

一、VueX是什么 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 库。它采用集中式存储管理应用的所有组件的状态&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。 二、为什么要用VueX “单向数据流”理念的简单示意&#xff1a; 当我们的应用遇到多个组…

Redis缓存

一.简介 缓存就是数据交换的缓冲区&#xff08;称作Cache [ kʃ ] &#xff09;&#xff0c;是存贮数据的临时地方&#xff0c;一般读写性能较高 二.添加Redis缓存 三.缓存更新策略 1.主动更新策略 Cache Aside Pattern(推荐) 需要调用者自己编码&#xff0c;但可控性高 Re…

SimSiam-Exploring Simple Siamese Pepresentation Learning

SimSiam Abstract 模型坍塌&#xff0c;在siamese中主要是输入数据经过卷积激活后收敛到同一个常数上&#xff0c;导致无论输入什么图像&#xff0c;输出结果都能相同。 而He提出的simple Siamese networks在没有采用之前的避免模型坍塌那些方法&#xff1a; 使用负样本lar…

K_A08_003 基于 STM32等单片机驱动L9110模块按键控制直流电机正反转加减速启停

目录 一、资源说明 二、基本参数 1、参数 2、引脚说明 三、驱动说明 L9110模块驱动时序 对应程序: PWM信号 四、部分代码说明 接线说明 1、STC89C52RCL9110模块 2、STM32F103C8T6L9110模块 五、基础知识学习与相关资料下载 六、视频效果展示与程序资料获取 七、项目主要…

【Android工具】群晖安卓客户端基础套件:Drive、video、Photos和DS video安卓TV客户端...

微信关注公众号 “DLGG创客DIY”设为“星标”&#xff0c;重磅干货&#xff0c;第一时间送达。最近终于把all in one搞起来了&#xff0c;all in one就是把一堆功能一堆软件装一台主机里。。all in one&#xff08;以后简称AIO&#xff09;相关内容回头慢慢聊。今天先聊聊群晖&…

从一个demo说elf文件

本文的demo是在linux环境下编译解析的&#xff0c;cpu是x86-64 首先我们先写一个功能简单的demo-SimpleSection.c。这个demo中有一个func1函数用来打印数据&#xff0c;一个已经初始化的全局变量global_init_var和未初始化的全局变量global_uninit_var&#xff0c;一个已初始化…

使用TS 封装 自定义hooks,实现不一样的 CRUD

文章目录使用TS 封装 自定义hooks&#xff0c;实现不一样的 CRUD自定义 hooks文件结构type.tsuseDelData.ts使用useFetchList.ts使用useInsert.ts使用部分的接口方法使用TS 封装 自定义hooks&#xff0c;实现不一样的 CRUD 这一篇主要是记录 查缺补漏&#xff0c;提升自己的 强…

三、内存管理 (一)存储器管理

目录 1.1程序运行的基本过程 1.1.1 编辑、编译、链接、装入 1.1.2链接的三种方式 1.1.3装入的三种方式 1.2内存管理基本概念 1.2.1内存保护 1.2.2内存空间扩充 1.2.3地址转换功能 1.2.4内存空间的分配与回收 1.2.4.1连续分配管理方式 1.2.4.1.1单一连续分配 1.2.4.1…

Http协议和Https协议

Http是不安全的&#xff0c;你的数据容易被黑客拦截&#xff0c;篡改&#xff0c;攻击 https要求对数据加密&#xff08;不能明文传输&#xff09;, 用抓包工具抓http请求&#xff0c;抓出来的都是明文的&#xff0c;你能看得懂的&#xff0c;抓https请求&#xff0c;抓出来的…

网站域名被QQ拦截提示:当前网页非官方页面拦截的解决办法

今天网友提醒&#xff0c;星空站长网的链接被QQ屏蔽拦截了。提示&#xff1a;当前页面非官方页面&#xff0c;请复制到浏览器打开。 如图&#xff1a; 原因&#xff1a;这是因为QQ方面的诈骗信息特别多&#xff0c;所以腾讯官方索性就直接屏蔽了所有的外部链接。让站长们通过申…

Python源码剖析笔记1-整数对象PyIntObject

1、PyIntObject 对象 [intobject.h] typedef struct {PyObject_HEADlong ob_ival; } PyIntObjectPyIntObject是一个不可变&#xff08;immutable&#xff09;对象。Python内部也大量的使用整数对象&#xff0c;我们在自己的代码中也会有大量的创建销毁整型对象的操作&#xff…

SVM 用于将数据分类为两分类或多分类(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

CMake中install的使用

CMake中的install命令用于指定安装时要运行的规则&#xff0c;其格式如下&#xff1a; install(TARGETS targets... [EXPORT <export-name>][RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>][[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDL…

基于单片机的电压电流表设计

原理图&#xff1a; 部分程序&#xff1a; #include "stc15.h" #include "delay.h" #include "timer.h" #include "TM7707.h" #include "LCD1602.h" #include "eeprom.h" #include "stdio.h" #include…