⬆️ ⬇️

Android UI Patterns: Dashboard

image After my recent article, several people inquired about how to make a Dashboard. Dashboard is one of the main UI patterns for Android, which you can read more about here . Search in a habr prompted as it is possible to implement QuickAction dialogs and ActionBar . In this article I will tell you how easy it is to make your Dashboard.



First we need this class:

import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; /** * Custom layout that arranges children in a grid-like manner, optimizing for even horizontal and * vertical whitespace. */ public class DashboardLayout extends ViewGroup { private static final int UNEVEN_GRID_PENALTY_MULTIPLIER = 10; private int mMaxChildWidth = 0; private int mMaxChildHeight = 0; public DashboardLayout(Context context) { super(context, null); } public DashboardLayout(Context context, AttributeSet attrs) { super(context, attrs, 0); } public DashboardLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { mMaxChildWidth = 0; mMaxChildHeight = 0; // Measure once to find the maximum child size. int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST); int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST); final int count = getChildCount(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth()); mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight()); } // Measure again for each child to be exactly the same size. childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( mMaxChildWidth, MeasureSpec.EXACTLY); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( mMaxChildHeight, MeasureSpec.EXACTLY); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } setMeasuredDimension( resolveSize(mMaxChildWidth, widthMeasureSpec), resolveSize(mMaxChildHeight, heightMeasureSpec)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int width = r - l; int height = b - t; final int count = getChildCount(); // Calculate the number of visible children. int visibleCount = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } ++visibleCount; } if (visibleCount == 0) { return; } // Calculate what number of rows and columns will optimize for even horizontal and // vertical whitespace between items. Start with a 1 x N grid, then try 2 x N, and so on. int bestSpaceDifference = Integer.MAX_VALUE; int spaceDifference; // Horizontal and vertical space between items int hSpace = 0; int vSpace = 0; int cols = 1; int rows; while (true) { rows = (visibleCount - 1) / cols + 1; hSpace = ((width - mMaxChildWidth * cols) / (cols + 1)); vSpace = ((height - mMaxChildHeight * rows) / (rows + 1)); spaceDifference = Math.abs(vSpace - hSpace); if (rows * cols != visibleCount) { spaceDifference *= UNEVEN_GRID_PENALTY_MULTIPLIER; } if (spaceDifference < bestSpaceDifference) { // Found a better whitespace squareness/ratio bestSpaceDifference = spaceDifference; // If we found a better whitespace squareness and there's only 1 row, this is // the best we can do. if (rows == 1) { break; } } else { // This is a worse whitespace ratio, use the previous value of cols and exit. --cols; rows = (visibleCount - 1) / cols + 1; hSpace = ((width - mMaxChildWidth * cols) / (cols + 1)); vSpace = ((height - mMaxChildHeight * rows) / (rows + 1)); break; } ++cols; } // Lay out children based on calculated best-fit number of rows and cols. // If we chose a layout that has negative horizontal or vertical space, force it to zero. hSpace = Math.max(0, hSpace); vSpace = Math.max(0, vSpace); // Re-use width/height variables to be child width/height. width = (width - hSpace * (cols + 1)) / cols; height = (height - vSpace * (rows + 1)) / rows; int left, top; int col, row; int visibleIndex = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } row = visibleIndex / cols; col = visibleIndex % cols; left = hSpace * (col + 1) + width * col; top = vSpace * (row + 1) + height * row; child.layout(left, top, (hSpace == 0 && col == cols - 1) ? r : (left + width), (vSpace == 0 && row == rows - 1) ? b : (top + height)); ++visibleIndex; } } } 


It is taken from the sources of the Google IO program and edited by some Roman Nurik, since the original contains some bugs. The class automatically places our buttons depending on their size, number, orientation of the screen.



Now we need to create an XML file dashboard_layout.xml (or with any other name) that needs to be put in the res / layout folder. In it, we will specify the drawable and text for each button, as well as the background for the entire layout

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" <!-   layout'a -> android:background="@drawable/background"> <!-        -> <com.illidane.animado.layouts.DashboardLayout android:layout_width="fill_parent" android:layout_height="fill_parent"> <Button android:id="@+id/home_btn_new_message" style="@style/DashboardButton" <!-   -> android:text="@string/btn_new_message" <!-   -> android:drawableTop="@drawable/home_new_message" /> <Button android:id="@+id/home_btn_messages" style="@style/DashboardButton" android:text="@string/btn_messages" android:drawableTop="@drawable/home_messages" /> <Button android:id="@+id/home_btn_preferences" style="@style/DashboardButton" android:text="@string/btn_preferences" android:drawableTop="@drawable/home_preferences" /> <Button android:id="@+id/home_btn_full_version" style="@style/DashboardButton" android:text="@string/btn_full_version" android:drawableTop="@drawable/home_upgrade" /> </com.illidane.animado.layouts.DashboardLayout> </LinearLayout> 


Now we lack the style for our button, in which we need to specify the parameters of the icon and text. Create a styles.xml file in the res / values ​​folder:

 <resources> <style name="DashboardButton"> <item name="android:layout_gravity">center_vertical</item> <item name="android:layout_width">wrap_content</item> <item name="android:layout_height">wrap_content</item> <item name="android:gravity">center_horizontal</item> <item name="android:drawablePadding">5dp</item> <item name="android:textSize">@dimen/text_size_small</item> <item name="android:textStyle">bold</item> <item name="android:textColor">@color/white</item> <item name="android:background">@null</item> </style> </resources> 


Similarly, you need to create files color.xml, dimens.xml and strings.xml in which you need to specify the colors, sizes and strings we need, or write them directly into styles.xml and dashboard_layout.xml.



After these actions, the final stage remains - to create an Activity:

 import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.Button; import android.widget.ImageButton; import android.widget.Toast; public class DashboardActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.dashboard_layout); final Context mContext = this; Button btnNewMessage = (Button) findViewById(R.id.home_btn_new_message); btnNewMessage.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { //     dashboard'a    Activity } }); Button btnMessages = (Button) findViewById(R.id.home_btn_messages); btnMessages.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { } }); Button btnPreferences = (Button) findViewById(R.id.home_btn_preferences); btnPreferences.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { } }); Button btnFullVersion = (Button) findViewById(R.id.home_btn_full_version); btnFullVersion.setOnClickListener(new OnClickListener() { public void onClick(View arg0) { } }); } } 


')

That's it, use it!

Source: https://habr.com/ru/post/130194/



All Articles