简体   繁体   中英

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. On the foreground i try to have three TextViews to display three numbers. For this I inflate a card.xml in the constructor of Card. The TextViews are displayed, but not at the right position. 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.

I also tried to use Guidelines to position the TextViews relative to its width. 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:

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()` has some rules that you are not strictly following. 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 . You will need to set the layout params to the new height and width. Add the following code to the end of 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. In the constructor for Card.java , add the following to set the constraints:

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 . match_parent is never appropriate in 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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