I have implemented my dashboard that is extending ViewGroup using code below. But the result does not displayed as I expected. Dashboard has the buttons as its children views that are properly displayed but the text inside of buttons has an abnormal alignment.
Would you be so kind to explain me why the button label has the positioning effect on resizing and positioning of its container while the one position is set by XML attribute 'gravity'?
What should be done to centering text inside buttons?
Probably, I need the explanation of methods onMeasure() and onLayout(). As I guess, the first method measures the container(dashboard) size by its children views sizes, and the second method changes the position of these children views inside container and resize its. Isn't it? But why the positions and sizes of children views have the effect in onMeasure()?
Thanks in advance.
MainDashboard.java
public class MainDashboard extends ViewGroup {
/*Attributes: */
private static final float DEFAULT_FACTOR = 0.2f;
private static final float DEFAULT_SPACING = 0.025f;
private static final int DEFAULT_ROW = 1;
private static final int DEFAULT_COL = 1;
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
/*Attribute variables: */
private float mFactor;
private float mSpacing;
private int mRow;
private int mCol;
private DeviceScreenSize dss;
private SCApplication app;
private int ell_size;
public MainDashboard(Context context) {
super(context, null);
}
public MainDashboard(Context context, AttributeSet attrs) {
super(context, attrs, 0);
init(context,attrs);
}
public MainDashboard(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs){
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MainDashboard);
mFactor = a.getFloat(R.styleable.MainDashboard_factor, DEFAULT_FACTOR);
mSpacing = a.getFloat(R.styleable.MainDashboard_spacing, DEFAULT_SPACING);
mRow = a.getInteger(R.styleable.MainDashboard_row, DEFAULT_ROW);
mCol = a.getInteger(R.styleable.MainDashboard_col, DEFAULT_COL);
app = (SCApplication)context.getApplicationContext();
dss= app.getScreenSize();
ell_size = (int) (Math.min(dss.getWidth(),dss.getHeight())*mFactor);
}
@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(widthMeasureSpec), 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 container_width = r - l;
int container_height = b - t;
final int count = getChildCount();
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;
}
int left, top;
int hSpace=(int)(mSpacing *container_width),
vSpace=(int)(2 * mSpacing * container_width);
int col, row;
int visibleIndex = 0;
for (int i = 0; i < visibleCount; i++) {
final View child = getChildAt(i);
row = visibleIndex / mCol;
col = visibleIndex % mCol;
left = hSpace * (col + 1) + ell_size * col;
top = vSpace * (row + 1) + ell_size * row;
child.layout(left, top, left + ell_size, top + ell_size);
++visibleIndex;
}
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:whatever="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/llRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:background = "#000000" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="7"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvMainTitle"
style="@android:style/TextAppearance.Large"
android:text="@string/main_title"
android:textColor="#4169E1"
/>
</LinearLayout>
<com.sample.myapp.MainDashboard
xmlns:android = "http://schemas.android.com/apk/res/android"
android:id="@+id/dash"
android:layout_width = "match_parent"
android:layout_height = "match_parent"
android:layout_weight = "1"
android:background = "#000000"
whatever:col="4">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn1"
android:text="1"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn2"
android:text="2"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn3"
android:text="3"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn4"
android:text="4"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn5"
android:text="5"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn6"
android:text="6"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn7"
android:text="7"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn8"
android:text="8"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn9"
android:text="9"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn10"
android:text="10"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn11"
android:text="11"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn12"
android:text="12"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn13"
android:text="13"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn14"
android:text="14"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn15"
android:text="15"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/DashboardButton"
android:id="@+id/btn16"
android:text="16"
/>
</com.sample.myapp.MainDashboard>
</LinearLayout>
styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<style name = "DashboardButton">
<item name = "android:textSize">14sp</item >
<item name = "android:textStyle">bold</item >
<item name = "android:textColor">#FFFFFF</item>
<item name = "android:gravity">center_horizontal</item >
<item name = "android:layout_gravity">center_vertical</item >
<item name = "android:background">@drawable/defaultbuttonselector</item >
<item name = "android:layout_width">wrap_content</item >
<item name = "android:layout_height">wrap_content</item >
</style>
</resources>
defaultbuttonselector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="rectangle" >
<corners android:radius="10.0dp" />
<stroke
android:width="2dp"
android:color="#4169E1" />
</shape>
</item>
<item android:state_pressed="true">
<shape android:shape="rectangle">
<corners android:radius="10.0dip" />
<stroke
android:width="3dp"
android:color="#00f2ff" />
</shape>
</item>
</selector>
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MainDashboard">
<attr name="factor" format="float" />
<attr name="spacing" format="float" />
<attr name="row" format="integer" />
<attr name="col" format="integer" />
</declare-styleable>
</resources>
MainActivity.java
public class MainActivity extends AppCompatActivity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}