Search code examples
androidandroid-layoutandroid-toolbarsearchviewandroid-coordinatorlayout

Searchview focus to move from center to toolbar Android


I want to build searchview in center of screen and when I focus I want to move into toolbar. Remove Searchview only from toolbar when I remove focus from SearchView. I don't won't in different activities/fragments. Something similar to this view. I tried some piece of code but lack of knowledge so I didn't succeed. Can someone guide me

<androidx.coordinatorlayout.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    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">

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll" />
    </com.google.android.material.appbar.AppBarLayout>

    <androidx.recyclerview.widget.RecyclerView
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

UPDATE

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appBar"
        android:layout_width="match_parent"
        android:layout_height="100dp"
        android:backgroundTint="@color/orange_lighter"
        android:gravity="bottom"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <androidx.appcompat.widget.SearchView
            android:id="@+id/consultationSearchView"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:layout_marginStart="16dp"
            android:layout_marginTop="16dp"
            android:layout_marginEnd="16dp"
           
            android:theme="@style/SearchViewTheme"
            app:closeIcon="@drawable/ic_cancel"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
            app:searchIcon="@drawable/ic_search" />

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

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/constraintLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

      // more views

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

Activity code

 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

class ExploreConsultationsActivity : BaseActivity() {

companion object {
const val CONSULTATION_COVER_LIST_KEY = "consultation_cover_list"
}

private val binding by lazy { ExploreConsultationsLayoutBinding.inflate(layoutInflater) }
val viewModel by viewModel<ExploreConsultationViewModel>()

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

fun setupViewModel() {
viewModel.categoriesList = intent?.getParcelableArrayListExtra(CONSULTATION_COVER_LIST_KEY)
}

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

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.removeSearchViewFocus.value = false
viewModel.queryText = newText
}
return true
}
})
setOnQueryTextFocusChangeListener { _, hasFocus ->
binding.appBar.setExpanded(!hasFocus)
isSelected = hasFocus
}
}
}


override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_DOWN) {
val view: View? = currentFocus
if (view is SearchView) {
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)
}
}

Solution

  • To achieve something similar to the gif that you attached , you can try this :

    In your activity_main.xml layout file :

    <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.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"
         />
    
       </com.google.android.material.appbar.AppBarLayout>
    
    
                 <!-- Scrollable content -->
    
    </androidx.coordinatorlayout.widget.CoordinatorLayout>
    

    In your MainActivity.java file :

    public class MainActivity extends Activity {
    
         private TextInputEditText txt;
         private AppBarLayout appBarLayout;
         
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            txt = findViewById(R.id.textField);
            appBarLayout = findViewById(R.id.appBar);
    
            //This code will collapse the AppBar according to the focus on the textField
            txt.setOnFocusChangeListener((v, hasFocus) -> {
               appBarLayout.setExpanded(!hasFocus);
            });
    }
    
    // Function to clear focus from the textfield when you touch outside the view
    
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (v instanceof SearchView.SearchAutoComplete) {
                Rect outRect = new Rect();
                v.getGlobalVisibleRect(outRect);
                if (!outRect.contains((int)event.getRawX(), (int)event.getRawY())) {
                    v.clearFocus();
                    InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
                }
            }
        }
        return super.dispatchTouchEvent( event );
      }
    }
    

    You can modify the layout further to achieve your desired look.