相关文章推荐
另类的牛肉面  ·  Dockerfile 和 Windows ...·  7 月前    · 
博学的煎饼  ·  [QT]- ...·  11 月前    · 
礼貌的小熊猫  ·  android混淆fastjson ...·  1 年前    · 
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风格的

     // 原来使用AppCompat风格不带ActionBar的
     <style name="MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
    // 与AppCompat风格不带ActionBar的对应的 material主题
    <style name="MyTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
    // 当前material风格主题(带ActionBar)
    <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:checkableBooleantrue可以激活chip,为false就像一个button
    android:checkedBoolean是否默认选中
    ------
    app:chipIcondrawableicon(默认在文侧)
    app:chipIconEnabledbooleanapp:chipIcon是否激活
    ------
    app:checkedIcondrawable左侧点击后的按钮(会覆盖chipIcon)
    app:checkedIconEnabledBooleanapp:checkedIcon是否激活(默认false)
    -------
    app:closeIcondrawable右侧按钮
    app:closeIconEnabledBooleanapp:closeIcon按钮是否激活
    -------
    app:chipBackgroundColorcolor背景颜色
    app:chipStrokeColorcolor描边颜色
    app:chipStrokeWidthdp描边宽度
    app:chipCornerRadiusdp圆角
    app:rippleColorcolor水波纹颜色
    android:elevationdp高度/深度(Z轴距离 default:0)
    app:shapeAppearancestyle自定义属性(需配合cornerFamily)
    cornerFamilyenum自定义切边样式(单独使用无效)
    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:singleLineBoolean是否保持一行false
    app:singleSelectionBoolean是否单选false
    app:checkedChipid默认选中
    app:chipSpacingHorizontaldp水平间距
    app:chipSpacingVerticaldp垂直间距
    chipGroup#checkedChipIdsint[]获取当前选中的view集合
    chipGroup#setOnCheckedChangeListener(ChipGroup,checkedId)点击选中(只针对设置app:singleSelection=“true"使用)
    chipGroup#setOnHierarchyChangeListeneronChildViewAdded(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联动的效果,例如这样:

    代码有点多,这里只看效果,具体细节请下载代码查看!

    原创不易,您的点赞就是对我最大的支持!

    分类:
    Android
  •