Toolbar

A control provided by the AndroidX library to replace the ActionBar.

The detailed information

The ActionBar is the title bar at the top of each Activity, which is displayed by default for any new project. However, it is limited to the top of the Activity and cannot achieve Material Design effects, so it is no longer recommended. You can set it to a theme without ActionBar in the res/values/styles.xml file. More recommended is the Toolbar, which not only inherits all the functions of ActionBar, but also has high flexibility and can cooperate with other controls to achieve some Material Design effects.

Specify a topic without ActionBar. There are two common topics:

  • Theme. AppCompat. NoActionBar. Represents a dark theme, which sets the main color of the interface to dark and the background color to light.
  • Theme. AppCompat. Light. NoActionBar. Represents a light body, which sets the main color of the interface to light and the background color to dark.

Add controls to XML:


      
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">// A new namespace is specified because many Material properties were added to the new system for compatibility with the old system. / / it often can be used in the development of MD / / XMLNS: app = "http://schemas.android.com/apk/res-auto" / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - / / Toolbar controls provided by appcompat library / / height is set to ActionBar height // Lets the Toolbar use a dark theme alone. // (The system theme is a light color, and the Toolbar will be a light color, so elements on it will automatically use dark colors to distinguish them from the main color, making the font black ugly.) // Specify the pop-up menu item as a light-colored theme separately. // (The Toolbar now has a dark theme, and if it contains a menu item, the pop-up menu item will also have a dark theme, which will be ugly.)<androidx.appcompat.widget.Toolbar
        android:layout_width="match_parent"                            
        android:layout_height="? attr/actionBarSize"
        android:id="@+id/toolbar"
        android:background="@color/colorPrimary"                              
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"                            
        app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
    
</LinearLayout>
Copy the code

Modify the text displayed on the title bar: Added the label attribute to the Activity. If not specified, the label content specified in the application is used by default.


      
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.material">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".ToolbarActivity"
            android:label="Toolbar"/>
    </application>
</manifest>
Copy the code

Add the action button: res directory -> Menu Folder -> New File (select Menu Resource File).

<? xml version="1.0" encoding="utf-8"? > <menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

// Define the action button with the item tag
// ------------------------------------------------------------------------
// app:showAsAction Specifies the display position of the button: (App namespace is also used for compatibility with earlier versions)
// always: always in the Toolbar, not if there is not enough screen space.
// ifRoom: displays in the Toolbar if screen space is sufficient, otherwise displays in the menu.
// never: displays in the menu forever.
// ------------------------------------------------------------------------
// Note: The Toolbar action button only displays the icon. The Action button in the menu displays only text.

    <item android:id="@+id/backup"
        android:icon="@drawable/ic_backup"
        android:title="Backup"
        app:showAsAction="always" />

    <item android:id="@+id/delete"
        android:icon="@drawable/ic_delete"
        android:title="Delete"
        app:showAsAction="ifRoom" />

    <item android:id="@+id/settings"
        android:icon="@drawable/ic_settings"
        android:title="Settings"
        app:showAsAction="never" />
</menu>
Copy the code

Modify code:

class ToolbarActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_toolbar)

        // Call setSupportActionBar and pass in an instance of the Toolbar.
        // This uses the Toolbar and makes it look and function the same as the ActionBar.
        setSupportActionBar(toolbar)
    }

    /** * This method loads the toolanto. XML menu file */
    override fun onCreateOptionsMenu(menu: Menu?).: Boolean {
        menuInflater.inflate(R.menu.toolbar, menu)
        return true
    }

    /** * handle button click events */
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            R.id.backup ->
                Toast.makeText(this."You clicked Backup",Toast.LENGTH_SHORT).show()
            R.id.delete ->
                Toast.makeText(this."You clicked Delete",Toast.LENGTH_SHORT).show()
            R.id.settings ->
                Toast.makeText(this."You clicked Settings",Toast.LENGTH_SHORT).show()
        }
        return true}}Copy the code

Sliding menu

The so-called sliding menu is a hidden menu option, rather than placed on the home screen, and then can be sliding to display the menu. This method saves screen space and achieves very good animation.

DrawerLayout

It is a layout in which you can put two direct child controls. The first child control is what is displayed in the home screen, and the second child control is what is displayed in the slide menu.

Modify the XML code:


      
<androidx.drawerlayout.widget.DrawerLayout
    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:id="@+id/drawerLayout">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="? attr/actionBarSize"
            android:id="@+id/toolbar"
            android:background="@color/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    </FrameLayout>

<! Slide menu display content, in fact, use any can be used, DrawerLayout does not limit the use of fixed controls. -->
<! However, the Android :layout_gravity property must be specified because it tells DrawerLayout whether the slide menu is on the left or right side of the screen. -->
<! -- Left: left. Right: Right. Start: Checks the system language. -->

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#FFF"
        android:text="This is menu"
        android:textSize="30sp" />

</androidx.drawerlayout.widget.DrawerLayout>
Copy the code

By default, menus can only be dragged out by dragging at the edge of the screen. Now add a navigation button to the far left of the Toolbar. Clicking the button will also display the contents of the slide menu.

class MainActivity : AppCompatActivity() {

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

        // Add navigation buttons for the slide menu
        // call getSupportActionBar() to get an instance of the ActionBar, even though the ActionBar is implemented by the Toolbar.supportActionBar? .let {// If the ActionBar is not empty, do the following.
            // Display the navigation button
            it.setDisplayHomeAsUpEnabled(true)
            // Set the navigation button icon.
            // In fact, the left-most button of the Toolbar is called the Home button,
            // Its default icon is a return arrow, meaning to return to the previous Activity, which has changed its default style and function.
            it.setHomeAsUpIndicator(R.drawable.ic_menu)
        }
    }

    ...

    /** * handle button click events */
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            // Handle the click event of the Home button. Its ID is always Android.r.home.
            // Call DrawerLayout openDrawer() to display the slide menu, where the argument is specified as in XML.
            android.R.id.home -> drawerLayout.openDrawer(GravityCompat.START)
            ...
        }
        return true}}Copy the code

NavigationView

NavigationView is a control provided in the Material library. It is not only designed strictly according to the Material Design requirements, but also can make the implementation of the sliding menu page very simple.

First add the dependency library:

    implementation 'com. Google. Android. Material: material: 1.1.0'
// make the image round
    implementation 'DE. Hdodenhof: circleimageview: 3.0.1'
Copy the code

Then go to res -> Menu -> New File (select Menu Resource File) :


      
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">

<! The group tag indicates a group, and single indicates that all menu items in the group are single-only. -->

    <item android:id="@+id/navCall"
        android:icon="@drawable/nav_call"
        android:title="Call"/>

    <item android:id="@+id/navFriends"
        android:icon="@drawable/nav_friends"
        android:title="Friends"/>

    <item android:id="@+id/navLocation"
        android:icon="@drawable/nav_location"
        android:title="Location"/>

    <item android:id="@+id/navMail"
        android:icon="@drawable/nav_mail"
        android:title="Mail"/>

    <item android:id="@+id/navTask"
        android:icon="@drawable/nav_task"
        android:title="Tasks"/>

    </group>
</menu>
Copy the code

Prepare headerLayout, which is a customized layout:


      
<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="180dp"
    android:padding="10dp"
    android:background="@color/colorPrimary">

    <de.hdodenhof.circleimageview.CircleImageView
        android:layout_width="70dp"
        android:layout_height="70dp"
        android:id="@+id/iconImage"
        android:src="@drawable/nav_icon"
        android:layout_centerInParent="true"/>
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tvMailText"
        android:layout_alignParentBottom="true"
        android:text="[email protected]"
        android:textColor="#FFF"
        android:textSize="14sp"/>
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/tvUserText"
        android:layout_above="@id/tvMailText"
        android:text="Tony Green"
        android:textColor="#FFF"
        android:textSize="14sp"/>

</RelativeLayout>
Copy the code

Modify the layout page code:


      
<androidx.drawerlayout.widget.DrawerLayout
    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:id="@+id/drawerLayout">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="? attr/actionBarSize"
            android:id="@+id/toolbar"
            android:background="@color/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

    </FrameLayout>
    
<! NavigationView --> NavigationView
    
   <com.google.android.material.navigation.NavigationView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:id="@+id/navView"
       android:layout_gravity="start"
       app:menu="@menu/nav_menu"
       app:headerLayout="@layout/navheader"/>

</androidx.drawerlayout.widget.DrawerLayout>
Copy the code

Handle click events for NavigationView’s menu items:

        // Handle click events for NavigationView's menu items
        navView.setCheckedItem(R.id.navCall)
        // Set a listener for the menu item selected event
        navView.setNavigationItemSelectedListener {
            // Handle the logic for menu item selection here
            // Close the slide menu and return true to indicate that the event has been handled.
            drawerLayout.closeDrawers()
            true
        }
Copy the code

Hover buttons and interactive prompts

Facade design is a very important design idea in MD, and hover button is one of the simplest and most representative facade design.

FloatingActionButton

It is a control provided in the Material library to make it easier to hover buttons. It uses colorAccent as the button’s color by default, and you can name the button by specifying an icon for what the button does.

Modify the layout code:


      
<androidx.drawerlayout.widget.DrawerLayout
    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:id="@+id/drawerLayout">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">.<! -- end: According to the system language, end means on the right if it is from left to right. Otherwise, end is on the left. -->
<! App :elevation="8dp" :elevation The larger the value, the larger the projection range, but the lighter the projection effect. Generally, use the default value. -->

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/fab"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            android:src="@drawable/ic_done"
            />

    </FrameLayout>.</androidx.drawerlayout.widget.DrawerLayout>
Copy the code

Handling click events:

// Handle the click event for the hover Button, just like a Button.
fab.setOnClickListener{
    Toast.makeText(this."FAB clicked",Toast.LENGTH_SHORT).show()
}
Copy the code

Snackbar

Tooltip:

  • The purpose of Toast is to tell the user what is happening now, but the user can only passively receive this event.
  • Snackbar allows you to add an interactive button to the prompt. (For example, you can undo actions the user is currently doing, such as accidentally deleting data.)
// Interactive prompt tool
Call make() to create a Snackbar object.
// The first argument can be any View of the current layout. Snackbar will use this View to automatically find the outermost layout and display the prompt information.
// Call setAction() to set an action
Snackbar.make(view,"Data deleted",Snackbar.LENGTH_SHORT).setAction("Undo"){
          Toast.makeText(this."Data restored",Toast.LENGTH_SHORT).show()
    }.show()
Copy the code

CoordinatorLayout

It’s an enhanced version of FrameLayout, provided by the AndroidX library. It works basically the same as FrameLayout in normal cases, but it has some additional Material abilities.

In fact, CoordinatorLayout can listen to all the child controls for various events and automatically respond to the most reasonable. For example, if the Snackbar suggestion above hides the float button, the CoordinatorLayout will automatically shift the internal FloatingActionButton upwards if it can listen to the Snackbar’s eject event. (Although the Snackbar is not a child, the first argument the Snackbar receives, View, specifies the view on which the Snackbar is triggered, and we pass in the FloatingActionButton itself, The FloatingActionButton is a child of the CoordinatorLayout, so the event can be heard.)


      
<androidx.drawerlayout.widget.DrawerLayout
    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:id="@+id/drawerLayout">

<! -- You replace FrameLayout, and the CoordinatorLayout itself is an enhanced version of FrameLayout, so there are no side effects. -->
    
    <androidx.coordinatorlayout.widget.CoordinatorLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.appcompat.widget.Toolbar
            android:layout_width="match_parent"
            android:layout_height="? attr/actionBarSize"
            android:id="@+id/toolbar"
            android:background="@color/colorPrimary"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/fab"
            android:layout_gravity="bottom|end"
            android:layout_margin="16dp"
            android:src="@drawable/ic_done"
            />

    </androidx.coordinatorlayout.widget.CoordinatorLayout>.</androidx.drawerlayout.widget.DrawerLayout>
Copy the code

Card layout

Card layout is also a new concept in MD, which allows elements on a page to look like they are in a card, with rounded corners and shadows.

MaterialCardView

It is an important control provided by the Material library for implementing card-like layout effects. In fact, it is also a FrameLayout, but with extra rounded corners and shadows, it will look like a three-dimensional citrus.


      
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp">

<! App :cardCornerRadius: Specifies the degree of the card corner -->
<! App :elevation: specify the card elevation -->
    
</com.google.android.material.card.MaterialCardView>
Copy the code

Then combine RecyclerView and Glide to show:

First add dependencies:

implementation 'androidx. Recyclerview: recyclerview: 1.1.0'
implementation 'com. Making. Bumptech. Glide: glide: 4.9.0'
Copy the code

Then define an entity class:

class Fruit(val name: String,val imageId:Int)
Copy the code

Then specify a custom layout for RecyclerView’s children:


      
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_margin="5dp"
    app:cardCornerRadius="4dp">

<! App :cardCornerRadius: Specifies the degree of the card corner -->
<! App :elevation: specify the card elevation -->

<! -- The MaterialCardView is a FrameLayout. There is no convenient way to locate the MaterialCardView. -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

<! ScaleType refers to the zoom mode of the image, and centerCrop refers to filling the ImageView with the image at its original scale and trimming off the parts that are out of the screen. -->

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:id="@+id/iv"
            android:scaleType="centerCrop" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/tv"
            android:layout_gravity="center_horizontal"
            android:layout_margin="5dp"
            android:textSize="16sp"/>

    </LinearLayout>

</com.google.android.material.card.MaterialCardView>
Copy the code

Prepare an adapter for RecyclerView:

class FruitAdapter(val mContext: Context,val mList:List<Fruit>):RecyclerView.Adapter<FruitAdapter.ViewHolder>() {

    inner class ViewHolder(view: View):RecyclerView.ViewHolder(view){
        val iv:ImageView = view.findViewById(R.id.iv)
        val tv:TextView = view.findViewById(R.id.tv)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitAdapter.ViewHolder {
        val view =LayoutInflater.from(mContext).inflate(R.layout.item_cardview,parent,false)
        return ViewHolder(view)
    }

    override fun getItemCount(a) = mList.size

    override fun onBindViewHolder(holder: FruitAdapter.ViewHolder, position: Int) {
        val fruit = mList[position]
        holder.tv.text = fruit.name
        Glide.with(mContext).load(fruit.imageId).into(holder.iv)
    }
}
Copy the code

Finally modify the code in MainActivity:

class MainActivity : AppCompatActivity() {

    val fruits = mutableListOf(Fruit("Apple", R.drawable.apple),
        Fruit("Banana", R.drawable.banana),
        Fruit("Orange", R.drawable.orange),
        Fruit("Watermelon", R.drawable.watermelon),
        Fruit("Pear", R.drawable.pear),
        Fruit("Grape", R.drawable.grape),
        Fruit("Pineapple", R.drawable.pineapple),
        Fruit("Strawberry", R.drawable.strawberry),
        Fruit("Cherry", R.drawable.cherry),
        Fruit("Mango", R.drawable.mango))

    val fruitList = ArrayList<Fruit>()

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

        initView()
        initData()
    }

    private fun initData(a) {
        initFruits()
        val layoutManager = GridLayoutManager(this.2)
        recyclerView.layoutManager = layoutManager
        val adapter = FruitAdapter(this,fruitList)
        recyclerView.adapter = adapter
    }

    private fun initFruits(a) {
        fruitList.clear()
        repeat(50) {val index = (0 until fruits.size).random()
            fruitList.add(fruits[index])
        }
    }

    private fun initView(a){... }... }Copy the code

Note: When introducing the Material library, also need to res/values/style.css. XML AppTheme parent Theme instead of the Theme. MaterialComponents. Light. NoActionBar, Otherwise, you may experience crash problems when using the following controls.

<resources>

    <! -- Base application theme. -->
    <style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
        <! -- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>
Copy the code

AppBarLayout

In the example above, you end up with RecyclerView blocking out the Toolbar because they’re all placed in CoordinatorLayout, which is a reinforced FrameLayout, The controls in FrameLayout are in the upper left corner by default, which creates occlusion. Because of CoordinatorLayout, there are some more ingenious solutions.

AppBarLayout is another tool provided in the Material library. It is actually a vertical LinearLayout that encapsulates a lot of rolling events inside and applies some MD design concepts.

There are only two steps to solve the above example:

  • Nest the Toolbar in AppBarLayout
  • Specify a layout behavior for RecyclerView

      
<androidx.drawerlayout.widget.DrawerLayout
    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:id="@+id/drawerLayout">

    <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">// Nest the Toolbar in AppBarLayout<androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="? attr/actionBarSize"
                android:id="@+id/toolbar"
                android:background="@color/colorPrimary"
                android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
            
        </com.google.android.material.appbar.AppBarLayout>
        

        <androidx.recyclerview.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/recyclerView"/ / toRecyclerViewSpecify a layout behaviorapp:layout_behavior="@string/appbar_scrolling_view_behavior"/>.</androidx.coordinatorlayout.widget.CoordinatorLayout>.</androidx.drawerlayout.widget.DrawerLayout>
Copy the code

In fact, when RecyclerView scrolls, AppBarLayout is notified of scrolling events. When AppBarLayout receives scrolling events, its child controls can specify how to respond to those events. Through the app:layout_scrollFlags property.

<androidx.appcompat.widget.Toolbar
    android:layout_width="match_parent"
    android:layout_height="? attr/actionBarSize"
    android:id="@+id/toolbar"
    android:background="@color/colorPrimary"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
// srcoll: Indicates that when the RV scrolls up, the Toolbar scrolls up and hides.
// enterAlways: indicates that when the RV scrolls down, the Toolbar scrolls down and redisplays.
// Snap: Indicates that when the Toolbar is not fully hidden or displayed, it will automatically choose to hide or show based on the current sliding distance.
    app:layout_scrollFlags="scroll|enterAlways|snap"/>
Copy the code

The drop-down refresh

SwipeRefreshLayout is the core class that implements the drop-down refresh function.

First add dependencies:

implementation 'androidx. Swiperefreshlayout: swiperefreshlayout: 1.1.0'
Copy the code

Modify the layout file:

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
    android:id="@+id/swipeRefresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/ / becauseRecyclerViewIt becomes a subclass, soapp:layout_behaviorThe declared layout behavior is also moved over.app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/recyclerView"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
    
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
Copy the code

Modify the MainActivity code:

private fun initView(a) {
    // Set the color of the drop-down refresh progress bar
    swipeRefresh.setColorSchemeResources(R.color.colorPrimary)
    // Set the listener for the pull-down refresh
    swipeRefresh.setOnRefreshListener {
        refreshFruits(adapter)
    }
}

private fun refreshFruits(adapter: FruitAdapter) {
    thread {
        // The local refresh operation is very fast, so we put the thread to sleep for two seconds to see the refresh effect.
        Thread.sleep(2000)
        // Switch back to the main thread
        runOnUiThread{
            initFruits()
            adapter.notifyDataSetChanged()
            // Call setRefreshing() and pass false to indicate the end of the refresh event and hide the refresh progress bar.
            swipeRefresh.isRefreshing = false}}}Copy the code

Collapsible title bar

CollapsingToolbarLayout

It is a layout that works on top of the Toolbar provided by the Material library. It makes the Toolbar much richer, not just to show a title bar, but to be very flashy.

Note that CollapsingToolbarLayout does not exist independently and was limited to be used as a direct child of AppBarLayout at design time. AppBarLayout must be a child of CoordinatorLayout.

Example (Kotlin) :

Create a detail page for the RecyclerView item:


      
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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=".FruitActivity">

<! -- Title bar -->
    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp">

<! The android:theme attribute specifies a theme, which is the same as the previous Toolbar, except for a more advanced Toolbar effect that requires the theme designation up a level. -->
<! The app:contentScrim property is used to specify the background color in CollapsingToolbarLayout as it collapses and after the collapse. When folded, this is a normal Toolbar. -->
<! -- app:layout_scrollFlags Scroll indicates that information rolls with it, exitUntilCollapsed indicates that information remains on the interface after folding and does not move out of the screen. -->
        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/collapsingToolbar"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

<! The advanced title bar is a combination of a normal title bar and an image.
<! -- app:layout_collapseMode specifies the collapse mode of the control in CollapsingToolbarLayout. Pin means the position is always the same and parallax means there will be a dislocation in the collapse toolbarLayout. -->

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/ivFruit"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"/>

            <androidx.appcompat.widget.Toolbar
                android:layout_width="match_parent"
                android:layout_height="? attr/actionBarSize"
                android:id="@+id/toolbar"
                app:layout_collapseMode="pin"/>

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

<! -- Content section -->
<! -- NestedScrollView (ScrollView, NestedScrollView)
<! Since CoordinatorLayout can already respond to scrolling events, it needs to use a layout like NestedScrollView or RecyclerView internally. -->
    <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="wrap_content"
            android:orientation="vertical">
            <com.google.android.material.card.MaterialCardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginBottom="15dp"
                android:layout_marginLeft="15dp"
                android:layout_marginRight="15dp"
                android:layout_marginTop="35dp"
                app:cardCornerRadius="4dp">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:id="@+id/tvFruitContent"
                    android:layout_margin="10dp"/>

            </com.google.android.material.card.MaterialCardView>
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>

<! -- Use app:layout_anchor to set an anchor so that the hover button will appear in the title bar area. -->
    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/ic_comment"
        app:layout_anchor="@id/appBar"
        app:layout_anchorGravity="bottom|end"/>

</androidx.coordinatorlayout.widget.CoordinatorLayout>
Copy the code

Modify the code in FruitActivity:

class FruitActivity : AppCompatActivity() {

    companion object{
        const val FRUIT_NAME = "fruit_name"
        const val FRUIT_IMAGE_ID = "fruit_image_id"
    }

    private var fruitName = ""
    private var fruitImageId = 0

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

        initView()
        initData()
    }

    private fun initData(a){ fruitName = intent.getStringExtra(FRUIT_NAME)? :""
        fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID,0)
        collapsingToolbar.title = fruitName
        Glide.with(this).load(fruitImageId).into(ivFruit)
        tvFruitContent.text = generateFruitContent(fruitName)
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when(item.itemId){
            android.R.id.home -> {
                finish()
                return true}}return super.onOptionsItemSelected(item)
    }

    private fun generateFruitContent(fruitName: String) = fruitName.repeat(500)

    private fun initView(a){ setSupportActionBar(toolbar) supportActionBar? .setDisplayHomeAsUpEnabled(true)}}Copy the code

Modify the code in the FruitAdapter and add the click event:

class FruitAdapter(val mContext: Context,val mList:List<Fruit>):RecyclerView.Adapter<FruitAdapter.ViewHolder>() {

    inner class ViewHolder(view: View):RecyclerView.ViewHolder(view){
        val iv:ImageView = view.findViewById(R.id.iv)
        val tv:TextView = view.findViewById(R.id.tv)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FruitAdapter.ViewHolder {
        val view =LayoutInflater.from(mContext).inflate(R.layout.item_cardview,parent,false)
        val holder = ViewHolder(view)
        holder.itemView.setOnClickListener{
            val position = holder.adapterPosition
            val fruit = mList[position]
            val intent = Intent(mContext,FruitActivity::class.java).apply {
                putExtra(FruitActivity.FRUIT_NAME,fruit.name)
                putExtra(FruitActivity.FRUIT_IMAGE_ID,fruit.imageId)
            }
            mContext.startActivity(intent)
        }
        return holder
    }

    override fun getItemCount(a) = mList.size

    override fun onBindViewHolder(holder: FruitAdapter.ViewHolder, position: Int) {
        val fruit = mList[position]
        holder.tv.text = fruit.name
        Glide.with(mContext).load(fruit.imageId).into(holder.iv)
    }
}
Copy the code

Make full use of system status bar space

After the Android 5.0 system, can through the Android: fitsSystemWindows attribute to the background of the status bar, or color.

In CoordinatorLayout, AppBarLayout, CollapsingToolbarLayout this nested structure layout, the control of the android: fitsSystemWindows attribute specifies into true, This means that the control will appear in the system status bar, and all parent layouts in the control layout structure will be set to this property.

Modify the layout code:


      
<androidx.coordinatorlayout.widget.CoordinatorLayout
    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=".FruitActivity"// Add attributesandroid:fitsSystemWindows="true">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="250dp"// Add attributesandroid:fitsSystemWindows="true">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/collapsingToolbar"
            android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
            app:contentScrim="@color/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"// Add attributesandroid:fitsSystemWindows="true">

        <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:id="@+id/ivFruit"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax"// Add attributesandroid:fitsSystemWindows="true"/>.</com.google.android.material.appbar.CollapsingToolbarLayout>
    </com.google.android.material.appbar.AppBarLayout>.</androidx.coordinatorlayout.widget.CoordinatorLayout>
Copy the code

Next set the status bar color to transparent in the program’s subject:

<resources>. // Define a theme specifically for FruitActivity. It inherits the parent theme and all its features, and is customized on top of it.<style name="FruitActivityTheme" parent="AppTheme">// Specify a transparent color for the status bar<item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>
Copy the code

Finally use this theme:


      
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.material">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">.<activity
            android:name=".FruitActivity"
            android:theme="@style/FruitActivityTheme">
        </activity>
    </application>
</manifest>
Copy the code

note

References:

Line 1 of code (Version 3)

Welcome to follow wechat official account:No reason also