【问题标题】:Problem with inflating xml-Layout on custom layout class在自定义布局类上膨胀 xml-Layout 的问题
【发布时间】:2019-03-25 04:03:41
【问题描述】:

我有一个自定义的 ConstraintLayout 类 (Card.java),它覆盖了 onDraw() 方法以在他的背景中绘制一个六边形。在前台,我尝试使用三个TextViews 来显示三个数字。 为此,我在 Card 的构造函数中填充了 card.xml。 TextViews 显示,但不在正确的位置。它们应该与卡片的宽度和高度相匹配,然后将自身定位到卡片的左上角和右上角以及卡片的底部。但是他们会做一些事情,比如缩小自己并转到左上角。

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

我还尝试使用指南来相对于其宽度定位 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

【问题讨论】:

  • @MikeM。如上所述,我已经尝试使用&lt;merge&gt; 而不是&lt;ConstraintLayout&gt;。我添加了一张图片,您可以在其中看到使用 &lt;merge&gt; 时卡片的外观。
  • 你没有说Card.java是如何添加到布局中的。如果您以编程方式将卡添加到 ConstraintLayout 中,您是否设置了它的约束?如果你不这样做,一切都会崩溃到(0,0)。发布更多关于如何将Card.java 添加到视图层次结构中的信息以获得更多帮助。
  • 糟糕,抱歉,我错过了那部分。好吧,你肯定想要&lt;merge&gt; 标签,因为否则你最终会得到一个额外的嵌套ConstraintLayout。除此之外,我不使用ConstraintLayout,所以我不确定我能提供更多帮助。对于那个很抱歉。不过,我会说,ConstraintLayout 对于这样一个相对简单的布局可能有点矫枉过正。如果你不是绝对需要它成为ConstraintLayout,你可以考虑尝试更直接的ViewGroup,比如RelativeLayout。 Cheticamp 提出了一个很好的观点。
  • @MikeM。我使用了 ConstraintLayout,因为我可以在指南的帮助下使用百分比边距。如果我可以制作一个具有百分比边距的 RelativeLayout,我会使用它,但我读到如果你需要类似的东西,ConstrainLayout 会更好。
  • @Cheticamp 我编辑了帖子,以便您可以看到我的activity_main.xml,它通常只是添加到MainAcivity。所以 Card 只是添加到 xml 中。我只是玩了一下它的约束,我注意到,当我将它设置为 0dp 时,完整的布局将与其父级匹配,并且 TextViews 也显示在右上角。但我想知道为什么当我将约束设置为wrap_content 时,文本比背景中的六边形更包裹

标签: java android android-layout android-custom-view


【解决方案1】:

'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 中布局的高度和宽度更改为0dpmatch_parent 永远不适合 ConstraintLayout

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

在相关说明中,您应该考虑using the merge facility 以避免嵌套ConstraintLayouts,正如其他人提到的那样。

【讨论】:

  • 这听起来很有帮助。我稍后会尝试:) 谢谢!
  • 好吧,它的第一部分修复了它!只需编辑onMeasure() 中的LayoutParams。不需要第二件事,因为我在card.xml 中使用了merge 而不是ConstraintLayout
猜你喜欢
  • 1970-01-01
  • 2012-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多