I want to implement new gmail like toolbar without nested scroll view, which is scroll able, but when scroll down background should be visible.
It will look like this:
I want to implement new gmail like toolbar without nested scroll view, which is scroll able, but when scroll down background should be visible.
It will look like this:
It's not a nested scrollview, Its recyclerView. If you want such a search bar, you can make it using CardView and Edittext or use Material searchbar library. You can place it locked at that position by using frameLayout or CoordinatorLayout.
Here is a sample Screen I made!.
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#dadada"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
app:cardUseCompatPadding="true"
android:layout_margin="8dp"
app:cardCornerRadius="8dp"
android:layout_width="match_parent"
android:layout_height="64dp">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="8dp"
android:src="@drawable/ic_menu_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:background="@android:color/transparent"
android:hint="Search..."
android:minWidth="100dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/imageView2"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
android:src="@drawable/ic_search_black_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</android.support.v7.widget.CardView>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</android.support.design.widget.CoordinatorLayout>
Here is the result.
You just need create custom one in your Activity layout like
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.design.widget.CoordinatorLayout
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:layout_margin="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</android.support.design.widget.AppBarLayout>
</android.support.v7.widget.CardView>
</android.support.design.widget.CoordinatorLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</android.support.constraint.ConstraintLayout>
And change style of your activity to "NoActionBar". For me it help.
For anyone who is trying to implement this with a RecyclerView
, just use item view types with different layouts.
BaseAdapter that holds the main data:
public class BaseAdapter extends RecyclerView.Adapter<BaseAdapter.BaseViewHolder>
@Override
@NonNull
public BaseViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
// this is the main adapter so by default
// it should display the main content.
// Notice the layout being inflated here
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_song_list, null);
return createViewHolder(v);
}
// BaseViewHolder is the ViewHolder of this adapter
protected BaseViewHolder createViewHolder(View view) {
return new BaseViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final BaseViewHolder holder, final int position) {
// Do something here
}
Now create an abstract adapter that extends the previous adapter:
public abstract class BaseHeaderAdapter extends BaseAdapter {
protected static final int ITEM_HEADER = 0;
protected static final int ITEM_LIST = 1;
@NonNull
@Override
public BaseAdapter.BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == ITEM_HEADER) {
// Notice the layout being inflated here
// This is a different layout
View view = LayoutInflater.from(activity).inflate(R.layout.item_tab_header, parent, false);
return createViewHolder(view);
}
// This will return the default layout from the extended adapter
return super.onCreateViewHolder(parent, viewType);
}
// BaseAdapter and BaseViewHolder are extended
@Override
protected BaseAdapter.BaseViewHolder createViewHolder(View view) {
// Notice: BaseHeaderAdapter is the current adapter
// BaseViewHolder is the extended holder
return new BaseHeaderAdapter.BaseViewHolder(view);
}
@Override
public int getItemCount() {
int superItemCount = super.getItemCount();
return superItemCount == 0 ? 0 : superItemCount + 1;
}
@Override
public int getItemViewType(int position) {
return position == 0 ? ITEM_HEADER : ITEM_LIST;
}
// This adapter's ViewHolder
public class BaseHeaderViewHolder extends BaseAdapter.BaseViewHolder {
...
}
}
Now the adapter that displays everything:
public class MyAdapter extends BaseHeaderAdapter
.....
@Override
protected BaseAdapter.BaseViewHolder createViewHolder(View view) {
return new MyAdapter.BaseViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull final BaseAdapter.BaseViewHolder holder, int position) {
if (holder.getItemViewType() == ITEM_HEADER) {
// do some stuff
holder.mHeaderTitle.setText("Header");
} else {
super.onBindViewHolder(holder, position - 1);
}
}
// The ViewHolder extends the BaseHeaderAdapter.BaseHeaderViewHolder
You can also solve this with an AppBarLayout
and a custom CoordinatorLayout.Behavior
. First, setup the layout in this way:
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior=".view.SearchBarBehaviour">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
.../>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
app:elevation="0dp">
<!-- the searchbar with a layout_margin and transparent background etc -->
<include layout="@layout/searchbar" />
</com.google.android.material.appbar.AppBarLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Note the custom behavior set to the SwipeRefreshLayout. It looks like that:
class SearchBarBehaviour(
context: Context,
attrs: AttributeSet
) : CoordinatorLayout.Behavior<View>(context, attrs) {
private var previousY: Float = 0f
override fun layoutDependsOn(
parent: CoordinatorLayout,
child: View, dependency: View
): Boolean = dependency is AppBarLayout
override fun onDependentViewChanged(
parent: CoordinatorLayout,
child: View,
dependency: View
): Boolean {
val currentY = dependency.y
// When the AppBarLayout scrolls, scroll the RecyclerView for the same distance
(child as SwipeRefreshLayout)
.getChildAt(0)
.scrollBy(0, (previousY - currentY).toInt())
previousY = currentY
return false
}
}
This obviously also works without a SwipeRefreshLayout
if you attach the behavior directly to a RecyclerView
/NestedScrollView
/... and adjust the line in the custom behaviour to scroll the child itself.
This solves the RecyclerView
resizing issue of the default ScrollingViewBehavior
which causes the RecyclerView
to pop up its items when scrolling down.
© 2022 - 2024 — McMap. All rights reserved.