MaterialButton
MaterialButtonToggleGroup
Chip
ChipGroup
ChipDrawable
ChipsView
ChipsInput
⚠️:本系列结合官方文档以及自己的理解编写,暂不涉及源码部分,全是使用!
system
: macOS
android studio
: 4.1.3
gradle
:gradle-6.5-bin.zip
project gradle
:4.1.3
kotilin
:1.5.0
ViewBinding
: true
material
:1.4.0
appcompat
:1.4.0
Material环境配置
首先需要将主题(theme)改成material风格的
<style name="MyTheme" parent="Theme.AppCompat.Light.NoActionBar" >
<style name="MyTheme" parent="Theme.MaterialComponents.Light.NoActionBar" >
<style name="MyTheme" parent="Theme.MaterialComponents.Light" >
主题参考链接
在xml中配置
默认不配置,看不出material
风格组件的变化
选择对应的主题,这里就可以显示出material
样式了
在已有的AppCompat主题中使用material主题控件
可以看到在AppCompat
主题中使用material
主题的空间会直接崩溃,他们之间是不兼容的...
若你的项目中在<application
中设置theme
主题为AppCompat
,那么我认为最好的解决办法为:
将需要用material
组件的activity
设置为material
主题即可!
温馨提示:material
主题兼容AppCompat
主题,AppCompat
主题不兼容material
主题
接下来就步入主题吧!
MaterialButton
最原始的按钮:
<com.google.android.material.button.MaterialButton
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="MD按钮" />
在文字某侧显示的materialButton:
<com.google.android.material.button.MaterialButton
style ="@style/Widget.MaterialComponents.Button.Icon"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="左侧有图标"
app:icon ="@drawable/ic_emoji_02"
app:iconGravity ="textStart"
app:iconPadding ="10dp"
app:iconSize ="40dp" />
app:iconPadding ="dp" 图标和文字的距离
app:iconSize ="dp" 图标的大小
app:iconGravity =“” 图标的模式
其他效果:
参数 说明 效果 左侧 app:iconGravity="textStart" 右侧 app:iconGravity="textEnd" 上侧 app:iconGravity="textTop" 可以看出,这里虽然实现了icon在文字的某一侧,但是图片为啥是黑色的??
我的原始图片长这样:
这里是需要再次设置icon的色调和色调模式:
如果需要正常显示可以这样设置:
<com.google.android.material.button.MaterialButton
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
app:iconTint ="@color/white"
app:iconTintMode ="multiply" />
app:iconTintMode="" 设置色调模式
app:iconTint=“” 设置色调颜色
什么是色调颜色?比如这样:
<com.google.android.material.button.MaterialButton
app:iconTint ="@color/red"
app:iconTintMode ="multiply" />
<com.google.android.material.button.MaterialButton
app:iconTint ="@color/red"
# app:iconTintMode ="multiply"
# app:iconTintMode ="add"
# app:iconTintMode ="src_over"
其余色调模式展示:
<com.google.android.material.button.MaterialButton
android:backgroundTint ="@color/red"
android:backgroundTintMode ="add" />
背景色调和上图表类似,就不多做样式
水波纹[app:rippleColor]
<com.google.android.material.button.MaterialButton
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="水波纹颜色"
app:rippleColor ="@color/red" />
<com.google.android.material.button.MaterialButton
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="描边(stroke)"
android:textAllCaps ="false"
app:cornerRadius ="30dp"
app:strokeColor ="@color/red"
app:strokeWidth ="1dp" />
常见的样式
文本样式:
<com.google.android.material.button.MaterialButton
style ="@style/Widget.MaterialComponents.Button.TextButton"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="文本样式"
android:textAllCaps ="false"
app:icon ="@drawable/ic_emoji_08" />
自带描边样式:
<com.google.android.material.button.MaterialButton
style ="?attr/materialButtonOutlinedStyle"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="自带描边样式"
android:textAllCaps ="false" />
自定义属性[app:shapeAppearance]
如果你需要自定义菱形边,你可以这样做:
可以参考官方 的一张图来理解一下:
materialButton常用属性小结:
参数 说明 app:icon 图标 app:iconPadding 图标和文字的距离 app:iconSize 图标的大小 app:iconGravity 图标的模式 app:iconTint 图标的色调 app:iconTintMode 图标的着色模式 app:cornerRadius 按钮圆角 app:strokeColor 按钮轮廓颜色 app:strokeWidth 按钮轮廓粗细 app:rippleColor 水波纹颜色 android:backgroundTint 背景色调 android:backgroundTintMode 背景色调模式 @style/Widget.MaterialComponents.Button.TextButton 文字样式
?attr/materialButtonOutlinedStyle 自带描边样式
app:shapeAppearance 自定义属性(需配合cornerFamily,cornerSize使用) cornerFamily 切边模式 cornerSize 切边大小
更多详细参数查看
MaterialButtonToggleGroup
文本样式:
<com.google.android.material.button.MaterialButtonToggleGroup
android:id ="@+id/materialButtonGroup1"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:orientation ="horizontal"
app:checkedButton ="@+id/bt2"
app:singleSelection ="true" >
<com.google.android.material.button.MaterialButton
android:id ="@+id/bt1"
style ="@style/Widget.MaterialComponents.Button.TextButton"
android:text ="深色模式"
<com.google.android.material.button.MaterialButton
android:id ="@+id/bt2"
style ="@style/Widget.MaterialComponents.Button.TextButton"
android:text ="浅色模式"
... />
<com.google.android.material.button.MaterialButton
android:id ="@+id/bt3"
style ="@style/Widget.MaterialComponents.Button.TextButton"
android:text ="跟随系统"
... />
</com.google.android.material.button.MaterialButtonToggleGroup >
温馨提示:MaterialButtonToggleGroup继承自LinearLayout
MaterialButtonToggleGroup参数介绍:
android:orientation 设置方向
app:singleSelection 是否为单选
app:checkedButton 默认选中
来看看效果:
为了防止超出屏幕,常使用MaterialButtonToggleGroup
时,我喜欢给他添加一个HorizontalScrollView
,用来避免超出屏幕
例如这样:
<HorizontalScrollView
android:layout_width ="match_parent"
android:layout_height ="wrap_content" >
<com.google.android.material.button.MaterialButtonToggleGroup
android:id ="@+id/materialButtonGroup2"
android:layout_width ="match_parent"
android:layout_height ="wrap_content" >
<com.google.android.material.button.MaterialButton
android:id ="@+id/bt4"
style ="?attr/materialButtonOutlinedStyle"
android:text ="语文" />
<com.google.android.material.button.MaterialButton
android:id ="@+id/bt5"
style ="?attr/materialButtonOutlinedStyle"
android:text ="数学" />
<com.google.android.material.button.MaterialButton
android:id ="@+id/bt6"
style ="?attr/materialButtonOutlinedStyle"
android:text ="英语"
android:textAllCaps ="false" />
</com.google.android.material.button.MaterialButtonToggleGroup >
</HorizontalScrollView >
当然,也可以通过动态代码来添加内容:
val materialButtonList = listOf(
MaterialButton(
this ,
null ,
R.attr.materialButtonOutlinedStyle
).apply { text = "历史" },
MaterialButton(
this
,
null ,
R.attr.materialButtonOutlinedStyle
).apply { text = "化学" },
MaterialButton(
this ,
null ,
R.attr.materialButtonOutlinedStyle
).apply { text = "音乐" },
MaterialButton(
this ,
null ,
R.attr.materialButtonOutlinedStyle
).apply { text = "美术" },
materialButtonList.forEach {
binding.materialButtonGroup2.addView(it)
来看看效果:
切换状态:
切换状态这里用到了SwitchMaterial
,奔着匠人精神的原则,本篇先不讲,后续一定会讲到!
这里的逻辑应该看一遍就明白了
首先监听到switch的状态,通过他的状态来判断是否是垂直|水平,在做对应的事情
这里的takeTrue是我写的一个小扩展,非0及true
fun Boolean .takeTrue (other: Int = 1 ) =
if (!this ) {
} else {
other
最简单的chip:
<com.google.android.material.chip.Chip
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="最简单的chip" />
chip有一些属性和materialButton都是通用的,这里就直接全介绍了!
<com.google.android.material.chip.Chip
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="左侧图片"
android:checkable =""
android:checked =""
app:chipIconEnabled =“”
app:checkedIcon =“”
app:closeIcon =“”
app:checkedIconEnabled =“”
app:closeIcon =“”
app:closeIconEnabled =“”
app:chipIcon ="@drawable/ic_emoji_01" />
参数 类型 说明 android:checkable Boolean true可以激活chip,为false就像一个button android:checked Boolean 是否默认选中 -- -- -- app:chipIcon drawable icon(默认在文侧) app:chipIconEnabled boolean app:chipIcon是否激活 -- -- -- app:checkedIcon drawable 左侧点击后的按钮(会覆盖chipIcon) app:checkedIconEnabled Boolean app:checkedIcon是否激活(默认false) -- -- --- app:closeIcon drawable 右侧按钮 app:closeIconEnabled Boolean app:closeIcon按钮是否激活 -- -- --- app:chipBackgroundColor color 背景颜色 app:chipStrokeColor color 描边颜色 app:chipStrokeWidth dp 描边宽度 app:chipCornerRadius dp 圆角 app:rippleColor color 水波纹颜色 android:elevation dp 高度/深度(Z轴距离 default:0) app:shapeAppearance style 自定义属性(需配合cornerFamily) cornerFamily enum 自定义切边样式(单独使用无效) cornerSize 自定义切边大小(单独使用无效)
<com.google.android.material.chip.ChipGroup
android:id ="@+id/chipGroup1"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
app:checkedChip ="@id/chipPython"
app:chipSpacingVertical ="5dp"
app:chipSpacingHorizontal ="@dimen/dp_40" >
<com.google.android.material.chip.Chip
android:text ="java" />
<com.google.android.material.chip.Chip
android:text ="kotlin" />
<com.google.android.material.chip.Chip
android:text ="c" />
<com.google.android.material.chip.Chip
android:text ="dart" />
<com.google.android.material.chip.Chip
android:text ="C#" />
<com.google.android.material.chip.Chip
android:text ="python" />
<com.google.android.material.chip.Chip
android:text ="JS" />
</com.google.android.material.chip.ChipGroup >
app:checkedChip 默认选中
app:chipSpacingHorizontal 水平距离
app:chipSpacingVertical 垂直间距
来看看效果图:
chipGroup#setOnCheckedChangeListener监听点击
注意,这段代码是无效的!只有在单选模式下可以使用,来看看官方解释:
Register a callback to be invoked when the checked chip changes in this group. This callback is only invoked in single selection mode.
注册一个回调,以便在该组中检查的芯片发生更改时调用。此回调仅在单一选择模式下调用。(百度翻译)
如果你想强行点击,你可以这样做:
binding.chipGroup1.forEach { childView ->
if (childView is Chip) {
childView.click {
"${childView.text} -${childView.isChecked} " toast this
childView.setOnCloseIconClickListener {
原理就是循环chipGroup中的每一个chip,都添加点击事件即可.
<HorizontalScrollView
android:layout_width ="match_parent"
android:layout_height ="wrap_content" >
<com.google.android.material.chip.ChipGroup
android:id ="@+id/chipGroup2"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
app:checkedChip ="@+id/chipChinese"
app:singleLine ="true"
app:singleSelection ="true" >
<com.google.android.material.chip.Chip
android:id ="@+id/chipChinese"
style ="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="语文" />
<com.google.android.material.chip.Chip
style ="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="数学" />
<com.google.android.material.chip.Chip
style ="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width ="wrap_content"
android:layout_height ="wrap_content"
android:text ="英语" />
</com.google.android.material.chip.ChipGroup >
</HorizontalScrollView >
chipGroup参数介绍:
app:singleLine ="true" 设置一行
app:singleSelection ="true" 单选
当然,也可以动态添加view,例如这样:
来看看效果图:
chipGroup参数总结:
参数 类型 说明 default app:singleLine Boolean 是否保持一行 false app:singleSelection Boolean 是否单选 false app:checkedChip id 默认选中 app:chipSpacingHorizontal dp 水平间距 app:chipSpacingVertical dp 垂直间距 chipGroup#checkedChipIds int[] 获取当前选中的view集合 chipGroup#setOnCheckedChangeListener (ChipGroup,checkedId) 点击选中(只针对设置app:singleSelection=“true "使用) chipGroup#setOnHierarchyChangeListener onChildViewAdded(parent: View?, child: View) onChildViewRemoved(parent: View?, child: View) 添加和删除监听
更多属性查看
style的使用总结:
@style/Widget.MaterialComponents.Chip.Action 默认
@style/Widget.MaterialComponents.Chip.Entry @style/@style/Widget.MyApp.Chip.Choice @style/Widget.MaterialComponents.Chip.Filter 默认右侧删除按钮,选中后会出现选中状态 选中会留色 在chipGroup中使用,选中后左侧会出现选中图标
如果你选中的同时想要有选中的图标并且自定义你选中的颜色,你可以这样做:
可以自定义一个选择器,当选中状态的时候,自定义你的颜色即可
ChipDrawable
ChipDrawable常配合editTextView来使用,例如这样
<androidx.appcompat.widget.AppCompatTextView
android:text ="ChipDrawable and Edit:" />
<androidx.appcompat.widget.AppCompatEditText
android:id ="@+id/edit"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:hint ="请输入4位" />
<com.google.android.material.button.MaterialButton
android:id ="@+id/btPrintEdit"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
android:text ="点我输出结果" />
ChipEditActivity:
val tempLength = 4
binding.edit.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged (s: CharSequence ?, start: Int , count: Int , after: Int ) {
override fun onTextChanged (
charSequence: CharSequence ,
start: Int ,
before: Int ,
count: Int
override fun afterTextChanged (editable: Editable ) {
if (editable.length % tempLength == 0 && editable.isNotEmpty()) {
val chip: ChipDrawable =
ChipDrawable.createFromResource(this @ChipEditActivity , R.xml.item_chip)
chip.text = editable.subSequence(editable.length - tempLength, editable.length)
chip.setBounds(0 , 0 , chip.intrinsicWidth, chip.intrinsicHeight)
val span = ImageSpan(chip)
editable.setSpan(
span,
editable.length - tempLength,
editable.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
R.xml.item_chip:
<?xml version="1.0" encoding="utf-8" ?>
<chip xmlns:android ="http://schemas.android.com/apk/res/android"
xmlns:app ="http://schemas.android.com/apk/res-auto"
android:textAppearance ="@style/ChipTextAppearance"
app:chipBackgroundColor ="@color/cccccc"
app:chipIcon ="@drawable/ic_emoji_05"
app:closeIconEnabled ="false"
app:closeIconTint
="@android:color/white" />
说实话,我感觉这个缺陷很大,因为他不能点击,我认为他只是一种“效果”..还有待发展
来看看效果:
其余细节,请下载代码查看..
ChipsInput
ChipsInput是老外开源的一个chips组件官方地址
不过已经有很多年没有维护了,使用起来也或多或少有一些bug
所以我就把他的module导入到我的项目中,改了改他的bug,也学习了一下他的代码思路
使用场景:
一些特定场景的输入框
<com.pchmn.materialchips.ChipsInput
android:id ="@+id/chips_input"
android:layout_width ="match_parent"
android:layout_height ="wrap_content"
app:hint ="下拉输入框[可输入 'e' 来搜索 em 小图标]"
app:maxRows ="3" />
自行探索:
app:chip_labelColor="@color/black"
app:chip_hasAvatarIcon="true"
app:chip_backgroundColor="@color/black"
app:chip_deletable="false"
app:hintColor="@color/black"
app:textColor="@color/black"
app:chip_deleteIconColor="@color/teal_200"
app:chip_detailed_textColor="@color/teal_200"
app:chip_detailed_backgroundColor="@color/teal_200"
app:chip_detailed_deleteIconColor="@color/teal_200"
app:filterable_list_backgroundColor="@color/teal_200"
app:filterable_list_textColor="@color/teal_200"
再来看看动态代码:
来看看效果:
可以看出,这里只定义了em1 - em9 的内容,所以只能搜索到这些.
另外还有一些监听,例如输入监听:
binding.chipsInput.addChipsListener(object : ChipsInput.ChipsListener {
override fun onChipAdded (chip: ChipInterface , newSize: Int ) {
Log.e(TAG, "chip added, $newSize " )
override fun onChipRemoved (chip: ChipInterface ?, newSize: Int ) {
Log.e(TAG, "chip removed, $newSize " )
override fun onTextChanged (text: CharSequence ?) {
Log.e(TAG, "chip text changed: " + text.toString())
其余细节请下载代码自行查看!
ChipsView
ChipsView也是老外写的一个开源的逐渐原文地址 ,这个也是很久没有维护了,还是用v7包写的,还有一些小bug,我还是吧他的module导入到我的项目中改了改,使用很简单!
ChipsView我是做了一个和chipGroup联动的效果,例如这样:
代码有点多,这里只看效果,具体细节请下载代码查看!
原创不易,您的点赞就是对我最大的支持!
3916
yechaoa
Material Design
Android