I need to get the following design.
- I need a way without using TabLayout/ViewPager.
- There is no swipe required while switching in between the fragments.
Could you please help to understand how this can be designed with Segmented Buttons?
I need to get the following design.
Could you please help to understand how this can be designed with Segmented Buttons?
On
To draw the outer/border section you can simply use a MaterialCardView as the parent by using the properties app:strokeWidth and app:strokeColor and add the MaterialButtonToggleGroup as a child of it. The MaterialButtonToggleGroup has the property app:singleSelection="true" to act as a single selection and the property app:selectionRequired="true" to disable the deselection effect.
Example:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:background="@android:color/black">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:cardBackgroundColor="@android:color/black"
app:cardCornerRadius="0dp"
app:strokeWidth="1dp"
app:strokeColor="@android:color/white">
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggleButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:background="@android:color/black"
app:singleSelection="true"
app:selectionRequired="true"
app:checkedButton="@id/button1">
<com.google.android.material.button.MaterialButton
style="@style/MyButtonStyle"
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="All"
android:insetTop="0dp"
android:insetLeft="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:cornerRadius="0dp"
app:rippleColor="@android:color/transparent"/>
<com.google.android.material.button.MaterialButton
style="@style/MyButtonStyle"
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Favourites"
android:insetTop="0dp"
android:insetLeft="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:cornerRadius="0dp"
app:rippleColor="@android:color/transparent"/>
</com.google.android.material.button.MaterialButtonToggleGroup>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
where style="@style/MyButtonStyle" is a custom style for each MaterialButton like the below:
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
<item name="backgroundTint">@color/button_background_color_selector</item>
<item name="android:textColor">@color/button_text_color_selector</item>
<item name="android:textAllCaps">false</item>
</style>
From above the @color/button_background_color_selector is the tab background color selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="#5F9EA0" android:state_checked="true"/>
<item android:color="@android:color/transparent" android:state_checked="false"/>
</selector>
and the @color/button_text_color_selector is the tab text color selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/white" android:state_checked="true"/>
<item android:color="@android:color/darker_gray" android:state_checked="false"/>
</selector>
Result:
For Custom Tab background Image:
In case you have a custom background Image for the MaterialButton you can't use anymore the MaterialButtonToggleGroup because it will throw an error like this:
"Attempted to get ShapeAppearanceModel from a MaterialButton which has an overwritten background"
A simple solution is to replace the current MaterialButtonToggleGroup with a LinearLayout something like below:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:background="@android:color/black">
<com.google.android.material.card.MaterialCardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:cardBackgroundColor="@android:color/black"
app:cardCornerRadius="0dp"
app:strokeWidth="1dp"
app:strokeColor="@android:color/white">
<LinearLayout
android:id="@+id/toggleButton"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_margin="5dp"
android:background="@android:color/black">
<com.google.android.material.button.MaterialButton
style="@style/MyButtonStyle"
android:id="@+id/button1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="All"
android:insetTop="0dp"
android:insetLeft="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:cornerRadius="0dp"
app:rippleColor="@android:color/transparent"/>
<com.google.android.material.button.MaterialButton
style="@style/MyButtonStyle"
android:id="@+id/button2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="Favourites"
android:insetTop="0dp"
android:insetLeft="0dp"
android:insetRight="0dp"
android:insetBottom="0dp"
app:cornerRadius="0dp"
app:rippleColor="@android:color/transparent"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
where style="@style/MyButtonStyle" now is the below:
<style name="MyButtonStyle" parent="Widget.MaterialComponents.Button">
<item name="backgroundTint">@null</item>
<item name="android:background">@drawable/button_background_drawable_selector</item>
<item name="android:checkable">true</item>
<item name="android:textColor">@color/button_text_color_selector</item>
<item name="android:textAllCaps">false</item>
</style>
From the above you can use the property android:background to add a custom background drawable selector. In our case the @drawable/button_background_drawable_selector is defined under the drawable folder like the below:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/my_drawable" android:state_checked="true"/>
<item android:drawable="@android:color/transparent" android:state_checked="false"/>
</selector>
And programmatically you have to handle which button is now selected by using the setChecked() method like the below:
MaterialButton button1 = findViewById(R.id.button1);
MaterialButton button2 = findViewById(R.id.button2);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button1.setChecked(true);
button2.setChecked(false);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
button2.setChecked(true);
button1.setChecked(false);
}
});
On
if material button cannot apply gradient background color, so you can use AppCompatToggleButton:
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.appcompat.widget.AppCompatToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_selector"
android:textOff="App"
android:checked="true"
android:textOn="App" />
<androidx.appcompat.widget.AppCompatToggleButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_selector"
android:checked="false"
android:textOff="favorite"
android:textOn="favorite" />
</LinearLayout>
button_selector.xml
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/gradient_button_background"/>
<item android:drawable="@drawable/default_button_background"/>
</selector>
gradient_button_background.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="#FFFFFF"
android:startColor="#00FF00"
android:type="linear" />
</shape>
default_button_background.xml
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#002196F3" />
</shape>
In code:
Reference: https://github.com/material-components/material-components-android/blob/master/docs/components/Button.md#toggle-button