Reputation: 957
How to split a menu like chrome browser as shown in the image:
This is my actual code
<menu 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"
tools:context="materialtest.vivz.slidenerd.activities.MainActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>
Upvotes: 6
Views: 1121
Reputation: 40830
You can use a custom DialogFragment
with a dialog window that has a limited size and biased to the top end of the screen using the gravity attribute.
Like normal fragments, DialogFragment
takes in any custom layout in onCreateView
.
Animation: The dialog window can have a customized style with windowEnterAnimation
and windowExitAnimation
to simulate the animation of showing/dismissing the menu.
Here's the demo:
class OptionsMenuDialog : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view = inflater.inflate(R.layout.dialog_options_menu, container, false)
return view
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState)
// adding dialog animation
dialog.window!!.attributes!!.windowAnimations = R.style.DialogAnimation
return dialog
}
override fun onStart() {
super.onStart()
dialog!!.window!!.let {
val params = it.attributes
// Change the dialog size
params.width = 600
params.height = 1000
// Bias the dialog to the top|end of the screen
params.gravity = Gravity.TOP or Gravity.END
it.attributes = params
}
}
}
Java version:
public class OptionsMenuDialog extends DialogFragment {
@Nullable
@org.jetbrains.annotations.Nullable
@Override
public View onCreateView(@NonNull @NotNull LayoutInflater inflater, @Nullable @org.jetbrains.annotations.Nullable ViewGroup container, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
return inflater.inflate(
R.layout.dialog_options_menu, container,
false
);
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
Dialog dialog =super.onCreateDialog(savedInstanceState);
dialog.getWindow().getAttributes().windowAnimations = R.style.DialogAnimation;
return dialog;
}
@Override
public void onStart() {
Window window = getDialog().getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
// Change dialog size
attributes.width = 600;
attributes.height = 1000;
// Bias the dialog to the top|end of the screen
attributes.gravity = Gravity.TOP | Gravity.END;
window.setAttributes(attributes);
super.onStart();
}
}
The DialogAnimation
:
<style name="DialogAnimation">
<item name="android:windowEnterAnimation">@anim/anim_in</item>
<item name="android:windowExitAnimation">@anim/anim_out</item>
</style>
Animations:
anim_in:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
android:duration="50"
android:fromXScale="1.0"
android:fromYScale="0.0"
android:toXScale="1.0"
android:toYScale="1.0" />
</set>
anim_out:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<scale
android:duration="50"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:toXScale="1.0"
android:toYScale="0.0" />
</set>
And the layout:
<?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"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@+id/back"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:padding="10dp"
android:src="@drawable/baseline_arrow_back_24"
app:layout_constraintEnd_toStartOf="@+id/bookmark"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/bookmark"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:padding="10dp"
android:src="@drawable/baseline_star_outline_24"
app:layout_constraintEnd_toStartOf="@+id/refresh"
app:layout_constraintStart_toEndOf="@+id/back"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="@+id/refresh"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:padding="10dp"
android:src="@drawable/baseline_refresh_24"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/bookmark"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="8dp"
android:fillViewport="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@+id/refresh">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="16dp"
android:text="New tab"
android:textSize="18sp" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
You can use RecyclerView
for efficiency; just used ScrollView
for simplicity.
Edit:
params.width = 600
,params.height = 1000
both are overlapping small devices (small DP devices) in the size of the Options menu. Any better option to overcome this?
You'd create an XML value for both for different screen sizes; usually in values/dimens.xml
The default dimens.xml would be something like:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="dialog_height">150dp</dimen>
<dimen name="dialog_width">100dp</dimen>
</resources>
The documentation show typical screen sizes that you would override their corresponding dimen resources:
Here's how other smallest width values correspond to typical screen sizes:
- 320dp: Typical phone screen (240x320 ldpi, 320x480 mdpi, 480x800 hdpi, etc.)
- 480dp: Large phone screen ~5" (480x800 mdpi)
- 600dp: 7” tablet (600x1024 mdpi)
- 720dp: 10” tablet (720x1280 mdpi, 800x1280 mdpi, etc.)
Android studio can generate that automatically with: File >> New >> Values Resource File
Then you can specify the desired screen width/height that you need to have a different size.
This post has more in depth how to handle that.
Eventually you'd retrieve them in the dialog fragment like, and that will take care of the device width/height to pick the appropriate value:
// Kotlin
override fun onStart() {
super.onStart()
val density = Resources.getSystem().displayMetrics.density
val width = (resources.getDimension(R.dimen.dialog_width) * density).toInt()
val height = (resources.getDimension(R.dimen.dialog_height) * density).toInt()
dialog!!.window!!.let {
val params = it.attributes
// Change dialog size
params.width = width
params.height = height
// Bias the dialog to the top|end of the screen
params.gravity = Gravity.TOP or Gravity.END
it.attributes = params
}
}
// Java
@Override
public void onStart() {
Window window = getDialog().getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
float density = Resources.getSystem().getDisplayMetrics().density;
int width = (int) (getResources().getDimension(R.dimen.dialog_width) * density);
int height = (int) (getResources().getDimension(R.dimen.dialog_height) * density);
attributes.width = width;
attributes.height = height;
// Bias the dialog to the top|end of the screen
attributes.gravity = Gravity.TOP | Gravity.END;
window.setAttributes(attributes);
super.onStart();
}
Upvotes: 1
Reputation: 11
Try the following code:
<menu 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"
tools:context="materialtest.vivz.slidenerd.activities.MainActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
<item
android:id="@+id/action_new"
android:orderInCategory="101"
android:title="@string/action_new"
app:showAsAction="never" />
</menu>
<!-- Second menu -->
<menu 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"
tools:context="materialtest.vivz.slidenerd.activities.MainActivity">
<item
android:id="@+id/action_save"
android:orderInCategory="102"
android:title="@string/action_save"
app:showAsAction="never" />
<item
android:id="@+id/action_print"
android:orderInCategory="103"
android:title="@string/action_print"
app:showAsAction="never" />
</menu>
Upvotes: 0
Reputation: 1318
You can implement dialogFragment and you can locate on the screen where you want.
Here is an example :
http://www.androidbegin.com/tutorial/android-dialogfragment-tutorial/
You can change the position of the dialog. You can find it out how it works here :
Changing position of the Dialog on screen android
Upvotes: 3