PK creative Spring Festival, I am participating in the “Spring Festival creative submission contest”, please see: Spring Festival creative submission Contest

In order to celebrate the New Year, we are going to produce a series of material design style components using the series. This is the first article to try the water 😊

Let’s take a look at today’s results:

MaterialButton

MaterialButtonToggleGroup
Chip

ChipGroup
ChipDrawable

ChipsView

ChipsInput

⚠️: this series of official documents and their own understanding of the preparation, not involved in the source part, all use!

The environment

  • 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 Environment Configuration

Set the theme

First you need to change the theme to material style

 // Use AppCompat style without ActionBar
 <style name="MyTheme" parent="Theme.AppCompat.Light.NoActionBar">
// Material theme corresponding to AppCompat style without ActionBar
<style name="MyTheme" parent="Theme.MaterialComponents.Light.NoActionBar">

// Current Material Style theme (with ActionBar)
<style name="MyTheme" parent="Theme.MaterialComponents.Light">
Copy the code

Subject Reference link

Configure in XML

Not configured by default, no material style component changes are visible




Select the corresponding theme, and the Material style will now be displayed

Use the Material theme control in the existing AppCompat theme

You can see in theAppCompatUse in topicsmaterialThe theme space will crash directly, they are incompatible…

If you set theme to AppCompat in

Will need to usematerialThe component’sactivitySet tomaterialTheme!

Tips: Material theme is compatible with AppCompat theme, but AppCompat theme is not compatible with Material theme

Let’s get to the point!

MaterialButton

The original button:

 <com.google.android.material.button.MaterialButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MD button" />
Copy the code

MaterialButton displayed on one side of the text:

<com.google.android.material.button.MaterialButton
      style="@style/Widget.MaterialComponents.Button.Icon"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Icon on the left"
      app:icon="@drawable/ic_emoji_02"
      app:iconGravity="textStart"
      app:iconPadding="10dp"
      app:iconSize="40dp" />
Copy the code
  • App :iconPadding=”dp” Distance between icon and text
  • App :iconSize= Size of the “dp” icon
  • App :iconGravity= “” icon mode

Other effects:

parameter instructions The effect
On the left side of the app:iconGravity=”textStart”
On the right side app:iconGravity=”textEnd”
upper app:iconGravity=”textTop”
It can be seen that the icon is on one side of the text, but why is the picture black?

My original image looked like this:




Here is the tone and tone mode to set the icon again:

If normal display is required, it can be set as follows:

 <com.google.android.material.button.MaterialButton
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
          .
         app:iconTint="@color/white"
         app:iconTintMode="multiply" />
Copy the code
  • App :iconTintMode=”” Set tone mode
  • App :iconTint= “” Set tone color

What is tonal color? Like this:

 <com.google.android.material.button.MaterialButton
          .
         app:iconTint="@color/red"
         app:iconTintMode="multiply" />
Copy the code

 <com.google.android.material.button.MaterialButton
            .
            app:iconTint="@color/red"
            # app:iconTintMode="multiply"
            # app:iconTintMode="add"
            # app:iconTintMode="src_over"

	 />
Copy the code

Display of other color modes:

multiply add src_over
The background color
 <com.google.android.material.button.MaterialButton
            .
            android:backgroundTint="@color/red"
            android:backgroundTintMode="add" />
Copy the code

The background tone is similar to the diagram above, so don’t do much styling

Water ripples [app: rippleColor]

<com.google.android.material.button.MaterialButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Water ripple color"
        app:rippleColor="@color/red" />
Copy the code

Stroke rounded corners

<com.google.android.material.button.MaterialButton
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="The stroke (stroke)." "
       android:textAllCaps="false"
       app:cornerRadius="30dp"
       app:strokeColor="@color/red"
       app:strokeWidth="1dp" />
Copy the code

Common styles

Text style:

 <com.google.android.material.button.MaterialButton
            style="@style/Widget.MaterialComponents.Button.TextButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Text Style"
            android:textAllCaps="false"
            app:icon="@drawable/ic_emoji_08" />
Copy the code

Effect:

Built-in Stroke style:

    <com.google.android.material.button.MaterialButton
            style="? attr/materialButtonOutlinedStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Own stroke style"
            android:textAllCaps="false" />
Copy the code

Custom attributes [app:shapeAppearance]

If you need to customize a diamond edge, you can do this:You can refer toThe officialTo understand:

Summary of common properties of materialButton:

parameter instructions
app:icon icon
app:iconPadding Distance between icon and text
app:iconSize Icon size
app:iconGravity Pattern of ICONS
app:iconTint Color of icon
app:iconTintMode Color mode for an icon
app:cornerRadius Button with rounded corners
app:strokeColor Button outline color
app:strokeWidth Outline size of the button
app:rippleColor Water ripple color
android:backgroundTint The background color
android:backgroundTintMode Background tone mode
@style/Widget.MaterialComponents.Button.TextButton Writing style
? attr/materialButtonOutlinedStyle Comes with stroke style
app:shapeAppearance Custom properties (use with cornerFamily,cornerSize)
cornerFamily Trimming mode
cornerSize Trimming the size

View more detailed parameters

MaterialButtonToggleGroup

Text style:

<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="Dark mode"
           .
           />
    
       <com.google.android.material.button.MaterialButton
           android:id="@+id/bt2"
           style="@style/Widget.MaterialComponents.Button.TextButton"
           android:text="Light color mode"
           . />

       <com.google.android.material.button.MaterialButton
           android:id="@+id/bt3"
           style="@style/Widget.MaterialComponents.Button.TextButton"
           android:text="Follow system"
           . />

</com.google.android.material.button.MaterialButtonToggleGroup>
Copy the code

Warm prompt: MaterialButtonToggleGroup inherited from LinearLayout

MaterialButtonToggleGroup parameter is introduced:

  • Android: Orientation Settings
  • App :singleSelection is a single option
  • App :checkedButton is checked by default

Take a look at the results:




In order to prevent off screen, often using MaterialButtonToggleGroup, add a HorizontalScrollView, I like to give him to avoid beyond the screen

For example:

<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="Chinese" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/bt5"
            style="? attr/materialButtonOutlinedStyle"
            android:text="Mathematics" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/bt6"
            style="? attr/materialButtonOutlinedStyle"
            android:text="English"
            android:textAllCaps="false" />

    </com.google.android.material.button.MaterialButtonToggleGroup>

</HorizontalScrollView>
Copy the code

Of course, you can also add content via dynamic code:

 val materialButtonList = listOf(
            MaterialButton(
                this.null,
                R.attr.materialButtonOutlinedStyle // Set the style dynamically
            ).apply { text = "History" },
            MaterialButton(
                this.null,
                R.attr.materialButtonOutlinedStyle // Set the style dynamically
            ).apply { text = "Chemistry" },
            MaterialButton(
                this.null,
                R.attr.materialButtonOutlinedStyle // Set the style dynamically
            ).apply { text = "Music" },
            MaterialButton(
                this.null,
                R.attr.materialButtonOutlinedStyle // Set the style dynamically
            ).apply { text = "Fine arts"},)// Dynamic add
        materialButtonList.forEach {
            binding.materialButtonGroup2.addView(it)
        }
Copy the code

Take a look at the results:


We use the switching state hereSwitchMaterial, running towards the principle of craftsman spirit, this first do not talk, will be talked about later!

The logic here should be clear once you read it

First listen to the state of the switch, through his state to determine whether the vertical | level, doing corresponding things

Here takeTrue is a small extension I wrote, non-0 and true

fun Boolean.takeTrue(other: Int = 1) =
    if (!this) {
        0
    } else {
        other
    }
Copy the code

Chip

The simplest chip:

 <com.google.android.material.chip.Chip
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="The simplest chip" />
Copy the code

Chip has some properties that are common to the materialButton, which are directly introduced here!

 <com.google.android.material.chip.Chip
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="Left picture"
         android:checkable=""
         android:checked=""
         app:chipIconEnabled=""
         app:checkedIcon=""
         app:closeIcon=""
         app:checkedIconEnabled=""
         app:closeIcon=""
         app:closeIconEnabled=""
         app:chipIcon="@drawable/ic_emoji_01" />
Copy the code
parameter type instructions
android:checkable Boolean True activates the chip, which is false like a button
android:checked Boolean Is it selected by default?
app:chipIcon drawable Icon (default on text side)
app:chipIconEnabled boolean App: Whether chipIcon is active
app:checkedIcon drawable Click the button on the left (it will overwrite chipIcon)
app:checkedIconEnabled Boolean App :checkedIcon active (default false)
app:closeIcon drawable The right button
app:closeIconEnabled Boolean App: Whether the closeIcon button is active
app:chipBackgroundColor color The background color
app:chipStrokeColor color Stroke color
app:chipStrokeWidth dp Stroke width
app:chipCornerRadius dp Rounded corners
app:rippleColor color Water ripple color
android:elevation dp Shadow color
app:shapeAppearance style Custom properties (requires a cornerFamily)
cornerFamily enum Custom cut edge style (not available alone)
cornerSize Custom cut edge size (invalid alone)

Effect:

instructions The effect
Some operations on icon
Click on the shadow

ChipGroup

multi-select

ChipGroup inherits from FlowLayout

Let’s start with the simplest use:

<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>
Copy the code
  • App :checkedChip is selected by default
  • App: chipSpacingHorizontal horizontal distance
  • App :chipSpacingVertical Vertical spacing

Take a look at the renderings:




ChipGroup# setOnCheckedChangeListener click

Note that this code is invalid! It can only be used in radio mode.

Register a callback to be invoked when the checked chip changes in this group. This callback is only invoked in single selection mode. Register a callback to be invoked when the chips checked in this group change. This callback is invoked only in single selection mode. (Baidu Translation)

If you want to force a click, you can do this:

// A bully can bend his bow
binding.chipGroup1.forEach { childView ->
	  if (childView is Chip) {
	      // Click listen
	      childView.click {
	          "${childView.text}-${childView.isChecked}" toast this
	      }
	
	      // Close the listener
	      childView.setOnCloseIconClickListener {
	
	      }
	  }
}
Copy the code

The principle is to loop through each chip in the chipGroup and add click events.

The radio

<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="Chinese" />

     <com.google.android.material.chip.Chip
         style="@style/Widget.MaterialComponents.Chip.Filter"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="Mathematics" />

     <com.google.android.material.chip.Chip
         style="@style/Widget.MaterialComponents.Chip.Filter"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="English" />

 	</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
Copy the code

ChipGroup parameters:

  • App :singleLine=”true” Set one line
  • App: singleSelection = “true” radio

Of course, you can also add views dynamically, for example:

Take a look at the renderings:




ChipGroup parameters:

parameter type instructions default
app:singleLine Boolean Whether to keep one line false
app:singleSelection Boolean Whether or not the radio false
app:checkedChip id Selected by default
app:chipSpacingHorizontal dp Horizontal spacing
app:chipSpacingVertical dp The vertical distance between
chipGroup#checkedChipIds int[] Gets the currently selected view collection
chipGroup#setOnCheckedChangeListener (ChipGroup,checkedId) Click Select (for Settings onlyApp: singleSelection = “true“The use of)
chipGroup#setOnHierarchyChangeListener onChildViewAdded(parent: View? , child: View)

onChildViewRemoved(parent: View? , child: View)
Add and remove listeners

View more Properties

Summary of use of style:

@ style/Widget MaterialComponents. Chip. The Action by default

@style/Widget.MaterialComponents.Chip.Entry @style/@style/Widget.MyApp.Chip.Choice @style/Widget.MaterialComponents.Chip.Filter
By default, the right delete button will be selected Selection will leave color When used in chipGroup, the check icon appears on the left


If you want to have the selected icon and customize the color you selected, you can do this:

You can customize a selector. When you select a state, you can customize your color

ChipDrawable

ChipDrawable is often used in conjunction with editTextView, for example

xml:

<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="Please enter 4 digits" />

 <com.google.android.material.button.MaterialButton
     android:id="@+id/btPrintEdit"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:text="Click on my output." />
Copy the code

ChipEditActivity:

// You can customize the length..
 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
         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
             )
         }
     }
 })
Copy the code

R.xml.item_chip:


      
<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"/>
Copy the code

To be honest, I feel this flaw is huge because it can’t click and I think it’s just an “effect”.. Still to develop

Take a look at the results:

For other details, please download the code to view..

ChipsInput

ChipsInput is an official address for chips components

However, it has not been maintained for many years, and it is more or less buggy to use

So I imported his Module into my project, corrected his bugs, and learned his code ideas

Usage Scenarios:

  • The search box
  • Some scenario-specific input fields

Use:

<com.pchmn.materialchips.ChipsInput
     android:id="@+id/chips_input"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     app:hint="Drop down input box [search em small icon by typing 'e']"
     app:maxRows="3" />
Copy the code

Explore by yourself:

  • 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″

Let’s look at dynamic code:Take a look at the results:




As you can see, only em1-EM9 is defined here, so that’s all you can search for.

There are other types of listener, such as input listener:

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?). {
          // Input listener
          Log.e(TAG, "chip text changed: " + text.toString())
      }
  })
Copy the code

Other details please download the code to view!

ChipsView

ChipsView is also an open source source written by foreigners gradually original address, this is also for a long time not to maintain, or use v7 package to write, there are some small bugs, I still import his module into my project to change, easy to use!

ChipsView I made a linkage effect with chipGroup, for example:

A little bit more code, here only look at the effect, specific details please download the code to view!

The complete code

Original is not easy, your praise is the biggest support for me!