1

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?

Kotlin Learner
  • 3,995
  • 6
  • 47
  • 127

1 Answers1

1

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

        }
    }
}

Zain
  • 37,492
  • 7
  • 60
  • 84
  • How did you fix the whole code? Can I get the working solution? – Kotlin Learner Jun 21 '22 at 02:48
  • Didn't that code work with you? – Zain Jun 21 '22 at 04:33
  • yes it work. I have few other question should I create new question ? or ask in this one. – Kotlin Learner Jun 21 '22 at 10:28
  • If it is related to this question feel free to ask.. If i found it needs a long answer i would tell you to open a new question. – Zain Jun 21 '22 at 10:37
  • I am trying to set title but it's not working, until it explit set in xml. – Kotlin Learner Jun 21 '22 at 10:43
  • How do you set the title – Zain Jun 21 '22 at 10:53
  • I think I can open a new [question](https://stackoverflow.com/q/72699648/11560810). I tried some code. Can you help me on this. – Kotlin Learner Jun 21 '22 at 11:04
  • No problem, One question regarding this above post. In animation view you can see when you focus in the searchview, the searchview move to top and which is very close to statusbar. So How can we give margin or padding? – Kotlin Learner Jun 21 '22 at 12:20
  • This is because the `SearchView` height is `android:layout_height="?attr/actionBarSize"` which is the default ActionBar height; and when the CollapsingToolbar collapse; its default height will be equal to the ActionBar one; So, you see the SearchView takes the entire height... To fix this you need to make the `SearchView` height less than the ActionBar height.. something like `"40dp"` for instance – Zain Jun 21 '22 at 13:19
  • A little thing I forgot to mention in this answer; add `android:animateLayoutChanges="true"` so that it can could add some animation when the margin changes. – Zain Jun 21 '22 at 13:22
  • Ok I'll add above attribute. But how can I give in top margin when collapse ? – Kotlin Learner Jun 21 '22 at 13:28
  • You can solve it by adding a bottom margin to the Toolbar.. like `android:layout_marginBottom="30dp"` – Zain Jun 21 '22 at 14:08
  • `android:animateLayoutChanges="true"` in `AppBarLayout ` or `Toolbar` ? – Kotlin Learner Jun 21 '22 at 14:58
  • Either the root layout `CoordinatorLayout` or `AppBarLayout` – Zain Jun 21 '22 at 14:59
  • I set to `AppBarLayout`. Thanks – Kotlin Learner Jun 21 '22 at 15:11