Java 在自定义布局类上扩展xml布局的问题

Java 在自定义布局类上扩展xml布局的问题,java,android,android-layout,android-custom-view,Java,Android,Android Layout,Android Custom View,我有一个定制的ConstraintLayout类(Card.java),它覆盖了onDraw()方法,在他的背景中绘制一个六边形。在前台,我尝试使用三个文本视图来显示三个数字。 为此,我在card的构造函数中膨胀了一个card.xml。文本视图将显示,但不在正确的位置。它们应该与卡片的宽度和高度相匹配,然后将其自身放置在卡片的左上角和右上角,另一个放置在卡片的底部。但它们会收缩到左上角 我试图将card.xml的根元素改为“merge”而不是“…ConstraintLayout”,但这并没有改变

我有一个定制的ConstraintLayout类(Card.java),它覆盖了
onDraw()
方法,在他的背景中绘制一个六边形。在前台,我尝试使用三个
文本视图来显示三个数字。
为此,我在card的构造函数中膨胀了一个
card.xml
。文本视图将显示,但不在正确的位置。它们应该与卡片的宽度和高度相匹配,然后将其自身放置在卡片的左上角和右上角,另一个放置在卡片的底部。但它们会收缩到左上角

我试图将card.xml的根元素改为“
merge
”而不是“…
ConstraintLayout
”,但这并没有改变任何东西

我还尝试使用指南来定位文本视图相对于其宽度的位置。我尽量避免使用固定的边距,因此当卡片大小发生变化时,文本总是在正确的位置

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>

'onMeasure()`有一些您没有严格遵守的内容。我看到这些规则被违反而不受惩罚,但我认为你被抓住了,但我们会继续努力

onMeasure()
中,您正在设置自定义版面的高度和宽度,但
ConstraintLayout
仍将版面理解为
wrap\u content
。您需要将布局参数设置为新的高度和宽度。将以下代码添加到onMeasure()的末尾:

第二个问题是,您正在将
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
<代码>匹配父项在约束列表中永远不合适

这是对正在发生的事情的图片描述:

在相关注释中,您应该考虑避免嵌套<代码>约束布局,如其他所提到的。

OnMead()中有一些您不严格遵循的。我看到这些规则被违反而不受惩罚,但我认为你被抓住了,但我们会继续努力

onMeasure()
中,您正在设置自定义版面的高度和宽度,但
ConstraintLayout
仍将版面理解为
wrap\u content
。您需要将布局参数设置为新的高度和宽度。将以下代码添加到onMeasure()的末尾:

第二个问题是,您正在将
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
<代码>匹配父项在约束列表中永远不合适

这是对正在发生的事情的图片描述:


在相关注释中,您应该考虑避免嵌套<代码>约束布局< /代码>,如其他所提到的。

@ MikeM。如上所述,我已经尝试使用
而不是
。我添加了一张图片,您可以在其中看到使用
时卡的外观。您不会说如何将
Card.java
添加到布局中。如果以编程方式将卡添加到
ConstraintLayout
中,是否设置其约束?如果不这样做,所有内容都将崩溃为(0,0)。发布有关如何将
Card.java
添加到视图层次结构的更多信息以获取更多帮助。哦,对不起,我错过了这一部分。好吧,你肯定需要
标记,否则你会得到一个额外的嵌套
ConstraintLayout
。除此之外,我不使用ConstraintLayout
,因此我不确定我是否可以进一步提供帮助。很抱歉。不过,我想说的是,对于这样一个相对简单的布局,
ConstraintLayout
可能有点过分了。如果你绝对不需要那是一个<代码>约束布局>代码,你可以考虑尝试一个更直接的<代码>视图组< /C> >,比如<代码> ReleLayOut<<代码>。“切蒂坎普也提出了一个很好的观点。”米肯。我使用ConstraintLayout是因为我可以在指导方针的帮助下使用百分比边距。如果我能用百分比边距做一个相对的布局,我会使用它,但我读到如果你需要这样的东西,ConstraintLayout会更好。@Cheticamp我编辑了这篇文章,这样你就可以看到我的
activity\u main.xml
,它通常被添加到
MainActivity
。因此,
只是在xml中添加的。我只是玩了一下它的约束,我注意到,当我将它设置为
0dp
时,完整的布局将与其父级匹配,并且
TextView
显示在右角。但我想知道,当我将约束设置为
wrap\u content
@MikeM时,为什么文本比背景中的六边形更具包装性。如上所述,我已经尝试使用
而不是
。我添加了一张图片,您可以在其中看到使用
时卡的外观。您不会说如何将
Card.java
添加到布局中。如果以编程方式将卡添加到
ConstraintLayout
中,是否设置其约束?如果不这样做,所有内容都将崩溃为(0,0)。发布有关如何将
Card.java
添加到视图层次结构的更多信息以获取更多帮助。哦,对不起,我错过了这一部分。好吧,你肯定需要
标记,否则你会得到一个额外的嵌套
ConstraintLayout
。除此之外,我不相信你
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);