膨胀问题 xml-自定义布局 class 上的布局
Problem with inflating xml-Layout on custom layout class
我有一个自定义的 ConstraintLayout class (Card.java),它覆盖了 onDraw()
方法以在他的背景中绘制一个六边形。在前台,我尝试用三个 TextViews
来显示三个数字。
为此,我在 Card 的构造函数中膨胀了一个 card.xml
。显示了 TextView,但未显示在正确的位置。它们应该匹配卡片的宽度和高度,然后将自己定位到卡片的左上角和右上角,一个定位到卡片的底部。但是他们会做一些事情,比如自己缩小并转到左上角。
我试图将 card.xml 的根元素更改为“merge
”而不是“...ConstraintLayout
”,但这并没有改变任何东西。
我还尝试使用 Guidelines 来相对于其宽度定位 TextView。我尽量避免使用固定边距,所以文本总是在正确的位置,当卡片的大小发生变化时也是如此。
Card.java:
public class Card extends ConstraintLayout {
private int mSize;
private Path mHexagon;
private Paint mPaintHexagon;
private TextView mT1, mT2, mT3;
public Card(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.card, this);
// Numbers
mT1 = findViewById(R.id.num1);
mT2 = findViewById(R.id.num2);
mT3 = findViewById(R.id.num3);
// Hexagon
mSize = Field.getHexSize(); // Size is used to calculate the
setPath();
mPaintHexagon = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintHexagon.setColor(0x50888888);
mPaintHexagon.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mHexagon, mPaintHexagon);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = 2 * mSize;
int height = (int) (Math.sqrt(3) * mSize);
Log.d(TAG, "Measure w:" + width + " h:" + height);
setMeasuredDimension(width, height);
}
}
card.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/num2"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:text="2"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/num1"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:text="1"
app:layout_constraintStart_toEndOf="@+id/num2"
app:layout_constraintEnd_toStartOf="@+id/num3"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/num3"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:text="3"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"/>
</android.support.constraint.ConstraintLayout>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
tools:context=".MainActivity"
android:background="@color/colorAccentDark"
android:padding="5dp">
<de.portugall.markus.takeiteasy.Card
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/card"/>
</android.support.constraint.ConstraintLayout>
Screenshot Card in Layout-Debug mode
'onMeasure()` 有一些您没有严格遵守的 rules。我看到违反这些规则而不受惩罚,但我认为你被抓住了,但我们会继续前进。
在 onMeasure()
中,您正在设置自定义布局的高度和宽度,但 ConstraintLayout
仍将布局理解为 wrap_content
。您需要将布局参数设置为新的高度和宽度。在onMeasure()
末尾添加如下代码:
// Although we have measured the layout, we need to tell ConstraintLayout in the
// LayoutParams that the size is not longer "wrap_content".
ViewGroup.LayoutParams lp = getLayoutParams();
lp.width = width;
lp.height = height;
setLayoutParams(lp);
您遇到的第二个问题是您将 ConstraintLayout
(card.xml) 添加到 ConstraintLayout
(您的自定义布局),但您没有设置约束。在 Card.java
的构造函数中,添加以下内容以设置约束:
ConstraintLayout layout = (ConstraintLayout) inflate(context, R.layout.card, this);
// We have added R.layout.card to a ConstraintLayout (this custom layout), so we need
// to make sure that it is constrained properly.
ConstraintSet cs = new ConstraintSet();
cs.clone(layout);
cs.connect(R.id.layout, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
cs.connect(R.id.layout, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
cs.connect(R.id.layout, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
cs.connect(R.id.layout, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
cs.applyTo(layout);
您需要将 card.xml
中布局的高度和宽度更改为 0dp
。 match_parent
在 ConstraintLayout
中永远不合适。
这是对正在发生的事情的图片描述:
在相关说明中,您应该考虑 using the merge facility 以避免其他人提到的嵌套 ConstraintLayouts
。
我有一个自定义的 ConstraintLayout class (Card.java),它覆盖了 onDraw()
方法以在他的背景中绘制一个六边形。在前台,我尝试用三个 TextViews
来显示三个数字。
为此,我在 Card 的构造函数中膨胀了一个 card.xml
。显示了 TextView,但未显示在正确的位置。它们应该匹配卡片的宽度和高度,然后将自己定位到卡片的左上角和右上角,一个定位到卡片的底部。但是他们会做一些事情,比如自己缩小并转到左上角。
我试图将 card.xml 的根元素更改为“merge
”而不是“...ConstraintLayout
”,但这并没有改变任何东西。
我还尝试使用 Guidelines 来相对于其宽度定位 TextView。我尽量避免使用固定边距,所以文本总是在正确的位置,当卡片的大小发生变化时也是如此。
Card.java:
public class Card extends ConstraintLayout {
private int mSize;
private Path mHexagon;
private Paint mPaintHexagon;
private TextView mT1, mT2, mT3;
public Card(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
inflate(context, R.layout.card, this);
// Numbers
mT1 = findViewById(R.id.num1);
mT2 = findViewById(R.id.num2);
mT3 = findViewById(R.id.num3);
// Hexagon
mSize = Field.getHexSize(); // Size is used to calculate the
setPath();
mPaintHexagon = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintHexagon.setColor(0x50888888);
mPaintHexagon.setStyle(Paint.Style.FILL);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mHexagon, mPaintHexagon);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = 2 * mSize;
int height = (int) (Math.sqrt(3) * mSize);
Log.d(TAG, "Measure w:" + width + " h:" + height);
setMeasuredDimension(width, height);
}
}
card.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/num2"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:text="2"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/num1"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:text="1"
app:layout_constraintStart_toEndOf="@+id/num2"
app:layout_constraintEnd_toStartOf="@+id/num3"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/num3"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:text="3"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"/>
</android.support.constraint.ConstraintLayout>
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
tools:context=".MainActivity"
android:background="@color/colorAccentDark"
android:padding="5dp">
<de.portugall.markus.takeiteasy.Card
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/card"/>
</android.support.constraint.ConstraintLayout>
Screenshot Card in Layout-Debug mode
'onMeasure()` 有一些您没有严格遵守的 rules。我看到违反这些规则而不受惩罚,但我认为你被抓住了,但我们会继续前进。
在 onMeasure()
中,您正在设置自定义布局的高度和宽度,但 ConstraintLayout
仍将布局理解为 wrap_content
。您需要将布局参数设置为新的高度和宽度。在onMeasure()
末尾添加如下代码:
// Although we have measured the layout, we need to tell ConstraintLayout in the
// LayoutParams that the size is not longer "wrap_content".
ViewGroup.LayoutParams lp = getLayoutParams();
lp.width = width;
lp.height = height;
setLayoutParams(lp);
您遇到的第二个问题是您将 ConstraintLayout
(card.xml) 添加到 ConstraintLayout
(您的自定义布局),但您没有设置约束。在 Card.java
的构造函数中,添加以下内容以设置约束:
ConstraintLayout layout = (ConstraintLayout) inflate(context, R.layout.card, this);
// We have added R.layout.card to a ConstraintLayout (this custom layout), so we need
// to make sure that it is constrained properly.
ConstraintSet cs = new ConstraintSet();
cs.clone(layout);
cs.connect(R.id.layout, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
cs.connect(R.id.layout, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
cs.connect(R.id.layout, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
cs.connect(R.id.layout, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
cs.applyTo(layout);
您需要将 card.xml
中布局的高度和宽度更改为 0dp
。 match_parent
在 ConstraintLayout
中永远不合适。
这是对正在发生的事情的图片描述:
在相关说明中,您应该考虑 using the merge facility 以避免其他人提到的嵌套 ConstraintLayouts
。