У меня есть собственный класс 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>
У 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
.
Это наглядное описание происходящего:
Что касается примечания, вам следует рассмотреть возможность использования средства слияния, чтобы избежать вложенных ConstraintLayouts
как уже упоминалось другими.
LayoutParams
вonMeasure()
. Вторая вещь не была нужна, потому что я использовалmerge
вместоConstraintLayout
вcard.xml
.