androidandroid-toolbarandroid-coordinatorlayoutandroid-collapsingtoolbarlayoutandroid-appbarlayout

How to use Appbar with toolbar in android


Hey I am working on search bar in android. I get the lead from this post. Now I want to try something more. Above post explanation in short :- I have searchview in the middle of screen. When we focus to on searchview we animate to go to top of screen and after remove focus goes to original position of search view. Now I want to show back arrow with initial screen load, look like this

Image 1

enter image description here

When we focus I need to show screen like this

Image 2

enter image description here

I tried some piece of code, but I am not succeed

ExploreConsultationsLayoutBinding.xml

<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"
  android:focusable="true">


  <com.google.android.material.appbar.AppBarLayout
    android:id="@+id/appBar"
    android:layout_width="match_parent"
    android:gravity="bottom"
    android:backgroundTint="@color/red_primary_80"
    android:layout_height="?attr/collapsingToolbarLayoutLargeSize"
    android:fitsSystemWindows="true">

      <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@color/black">

    <androidx.appcompat.widget.SearchView
        android:id="@+id/searchView"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:layout_marginStart="16dp"
        app:iconifiedByDefault="false"
        android:layout_marginEnd="16dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
     />

     </androidx.appcompat.widget.Toolbar>

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


             <!-- Scrollable content -->

</androidx.coordinatorlayout.widget.CoordinatorLayout>

ExploreConsultationsActivity.kt

package com.example.app.consultation

import android.content.Context
import android.graphics.Rect
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.widget.SearchView
import com.example.app.common.BaseActivity
import com.example.app.databinding.ExploreConsultationsLayoutBinding
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf

class ExploreConsultationsActivity : BaseActivity() {

    companion object {
        const val CONSULTATION_LIST_KEY = "consultation_list"
    }

    private val binding by lazy { ExploreConsultationsLayoutBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        setupView()
    }

    fun setupView() {
        hideActionBar()
        setupSearchView()
    }

    fun hideActionBar() {
        supportActionBar?.let { actionBar ->
            actionBar.hide()
        }
    }

    fun setupSearchView() {
        binding.consultationSearchView.apply {
            setOnQueryTextListener(object : SearchView.OnQueryTextListener {
                override fun onQueryTextSubmit(query: String?) = false
                override fun onQueryTextChange(newText: String?): Boolean {
                    if (newText != null) {
                        viewModel.queryText = newText
                    }
                    return true
                }
            })
            setOnQueryTextFocusChangeListener { view, hasFocus ->
                binding.appBar.setExpanded(!hasFocus)
                if (hasFocus) {
                    binding.toolbar.apply {
                        setSupportActionBar(this)
                        supportActionBar?.setDisplayHomeAsUpEnabled(true)
                    }
                } else {
                    supportActionBar?.setDisplayHomeAsUpEnabled(false)
                }
                isSelected = hasFocus
            }
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
        if (ev?.action == MotionEvent.ACTION_DOWN) {
            val view: View? = currentFocus
            if (view is SearchView.SearchAutoComplete) {
                val outRect = Rect()
                view.getGlobalVisibleRect(outRect);
                if (!outRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
                    view.clearFocus()
                    val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
                }
            }
        }
        return super.dispatchTouchEvent(ev)
    }
}

Mainfest.xml

<activity android:name="ExploreConsultationsActivity"
            android:screenOrientation="portrait"
            android:theme="@style/NoActionBar"/>

Style.xml

<style name="NoActionBar" parent="@style/Theme.MaterialComponents.Light.NoActionBar">
        <item name="colorPrimary">@color/abc</item>
        <item name="colorPrimaryDark">@color/xyz</item>
        <item name="colorAccent">@color/abc</item>
        <item name="android:theme">@style/AppTheme</item>
        <item name="android:colorBackground">@color/white</item>
        <item name="android:windowActionBar">false</item>
        <item name="android:windowNoTitle">true</item>
        <item name="android:statusBarColor">@color/status_bar</item>
        <item name="android:windowLightStatusBar" tools:ignore="NewApi">true</item>
</style>

Actual Output

enter image description here

enter image description here

Expected Output

Image 1 and Image 2 please look top image of question.

Github Project

UPDATE

enter image description here

my search view is very close to status bar so how can I give top margin or padding?


Solution

  • You could change the start margin of the SearchView when it got the focus; and return it to the original margin when it loses the focus:

    var originalMargin = 0
    fun setupSearchView() {
        binding.consultationSearchView.apply {
            setOnQueryTextListener(object : SearchView.OnQueryTextListener {
                override fun onQueryTextSubmit(query: String?) = false
                override fun onQueryTextChange(newText: String?): Boolean {
                    if (newText != null) {
                    }
                    return true
                }
            })
    
            val params =
                binding.consultationSearchView.layoutParams as CollapsingToolbarLayout.LayoutParams
            originalMargin = params.marginStart
    
            setOnQueryTextFocusChangeListener { view, hasFocus ->
                binding.appBar.setExpanded(!hasFocus)
                isSelected = hasFocus
    
                if (hasFocus)
                    params.marginStart = originalMargin + 150 // arbitrary constant
                else
                    params.marginStart = originalMargin
                view.layoutParams = params
    
            }
        }
    }