我已经使用下面的代码实现了扩展ViewGroup的仪表板。但结果并没有像我预期的那样显示出来。仪表板将按钮作为其子视图正确显示,但按钮内的文本具有异常对齐。
您是否善意解释为什么按钮标签对其容器的大小调整和定位具有定位效果,而一个位置是由XML属性“gravity”设置的?
如何将按钮中的文本居中?
可能我需要onMeasure()和onLayout()方法的解释。我猜,第一种方法通过子视图大小测量容器(仪表板)大小,第二种方法更改容器内这些子视图的位置并调整其大小。不是吗?但为什么儿童观点的位置和大小对onMeasure()有影响?
提前致谢。
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);
}
}
答案 0 :(得分:0)
经过一些有根据的猜测和撕裂我的头发后,我找到了解决这个问题的方法。
关键在于ell_size
正文中我自己的情况(自定义信息中心的每个子项遇到大小onMeasure()
)我只使用ell_size
来设置{{1} }和childWidthMeasureSpec
而不是childHeightMeasureSpec
和widthMeasureSpec
。
我不知道这是否是一个很好的想法,但这对我有帮助,而且我得到了我需要的。
上面代码的片段:
heightMeasureSpec
我从功能private void init(Context context, AttributeSet attrs){
...
ell_size = (int) (Math.min(dss.getWidth(),dss.getHeight())*mFactor);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Measure once to find the maximum child size.
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
ell_size, MeasureSpec.AT_MOST);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
ell_size, 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);
}
// Measure again for each child to be exactly the same size.
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
ell_size, MeasureSpec.EXACTLY);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
ell_size, 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(ell_size, widthMeasureSpec),
resolveSize(ell_size, heightMeasureSpec));
}
的描述中找到了这个想法:
为视图及其所有后代指定大小和位置。这个 是布局机制的第二阶段。 (第一个是测量)。 在此阶段,每个父级都会调用其所有子级上的布局 定位他们。这通常使用子测量来完成 存储在measure pass()中的。派生类不应该 覆盖此方法。带子项的派生类应该覆盖 onLayout。在那种方法中,他们应该在每个方法上调用布局 孩子。