Проблема с накачкой xml-Layout в пользовательском классе макета

1

У меня есть собственный класс ConstraintLayout (Card.java), который переопределяет метод onDraw() для рисования шестиугольника на его фоне. На переднем плане я пытаюсь иметь три TextViews для отображения трех чисел. Для этого я card.xml в конструкторе Card. TextViews отображаются, но не в правильном положении. Они должны соответствовать ширине и высоте Карты, а затем располагаться в верхнем левом и правом верхнем углу и один в нижней части Карты. Но они делают что-то вроде сокращения и идут в верхний левый угол.

Я попытался изменить корневой элемент card.xml на " merge " вместо "... ConstraintLayout ", но это ничего не меняет.

Я также попытался использовать Guidelines для позиционирования TextViews относительно его ширины. Я стараюсь не использовать фиксированные поля, поэтому текст всегда находится в нужном месте, даже когда размер карты меняется.

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>

Скриншот карты в режиме Layout-Debug

Теги:
android-custom-view
android-layout

1 ответ

0
Лучший ответ

У onMeasure() есть некоторые правила, которые вы не строго соблюдаете. Я видел эти правила нарушенными безнаказанно, но я думаю, что вас поймали, но мы будем настаивать.

В 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.

Это наглядное описание происходящего:

Изображение 174551

Что касается примечания, вам следует рассмотреть возможность использования средства слияния, чтобы избежать вложенных ConstraintLayouts как уже упоминалось другими.

  • 0
    это звучит действительно полезно. Попробую позже :) Спасибо!
  • 0
    хорошо, первая часть исправила это! Просто нужно отредактировать LayoutParams в onMeasure() . Вторая вещь не была нужна, потому что я использовал merge вместо ConstraintLayout в card.xml .

Ещё вопросы

Сообщество Overcoder
Наверх
Меню