简体   繁体   English

在自定义布局类上膨胀xml-Layout的问题

[英]Problem with inflating xml-Layout on custom layout class

I have a custom ConstraintLayout class (Card.java) which overrides the onDraw() method to draw a hexagon in his background. 我有一个自定义的ConstraintLayout类(Card.java),该类重写onDraw()方法在其背景中绘制一个六边形。 On the foreground i try to have three TextViews to display three numbers. 在前台,我尝试使用三个TextViews显示三个数字。 For this I inflate a card.xml in the constructor of Card. 为此,我在Card的构造函数中为card.xml充气。 The TextViews are displayed, but not at the right position. 显示的是TextView,但位置不正确。 They should match the width and height of the Card and then position itself to the top-left and top-right corner and one to the bottom of the Card. 它们应与卡的宽度和高度匹配,然后将其自身放置在卡的左上角和右上角,并放置在卡的底部。 But they do something like shrink itself and go to the top-left corner. 但是它们会像收缩自身一样移动到左上角。

I have tried to change the root element of card.xml to " merge " instead of "... ConstraintLayout " but this doesn't change anything. 我试图将card.xml的根元素更改为“ merge ”,而不是“ ... ConstraintLayout ”,但这没有任何改变。

I also tried to use Guidelines to position the TextViews relative to its width. 我还尝试使用准则将TextViews相对于其宽度定位。 I try to prevent the use of fixed margins, so the Text is always at the right place, also when the size of the Card changes. 我试图防止使用固定的边距,因此当卡片大小改变时,文本始终在正确的位置。

Card.java: 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: 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: 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()` has some rules that you are not strictly following. 'onMeasure()`有一些您不严格遵守的规则 I have seen these rules broken with impunity, but I think that you are being caught, but we will push on. 我已经看到这些规则不受惩罚地遭到破坏,但是我认为您被抓住了,但是我们会继续前进。

In onMeasure() you are setting the height and width of the custom layout but ConstraintLayout still understands the layout as wrap_content . onMeasure()您可以设置自定义布局的高度和宽度,但是ConstraintLayout仍将布局理解为wrap_content You will need to set the layout params to the new height and width. 您将需要将布局参数设置为新的高度和宽度。 Add the following code to the end of onMeasure() : 将以下代码添加到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);

The second issue that you have is that you are adding a ConstraintLayout (card.xml) to a ConstraintLayout (your custom layout), but you are not setting the constraints. 您遇到的第二个问题是将ConstraintLayout (card.xml)添加到ConstraintLayout (您的自定义布局)中,但是没有设置约束。 In the constructor for Card.java , add the following to set the constraints: 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);

You will need to change the height and width of the layout in card.xml to 0dp . 您将需要将card.xml布局的高度和宽度更改为0dp match_parent is never appropriate in ConstraintLayout . match_parent永远不适用于ConstraintLayout

This is a pictorial description of what is happening: 这是正在发生的情况的图形描述:

在此处输入图片说明

On a related note, you should consider using the merge facility to avoid nested ConstraintLayouts as other have mentioned. 与此相关的是,您应该考虑使用合并工具来避免嵌套ConstraintLayouts就像其他人提到的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM