I've created some custom views based on ContraintLayout, which is basically a pairing of a textview and some other component.
EditTextCompat and SwitchCompat. Both of them are basically created the same way but only the "interactive" part differs.
When I use the CustomEditTextCompat and use it as layout_constraintTop_toBottomOf="CustomEditTextCompat" it works as expected. But when I do the same and try to use the CustomSwitchCompat as a constraint the view just jumps to the top.
Any suggestions?
custom_switch_compat.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content"
tools:background="@color/black">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerLeft_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.49" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerRight_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.51" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/switchTextLabel"
style="@style/ColorAndFontTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="13dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@+id/centerLeft_line"
app:layout_constraintTop_toTopOf="parent"
tools:text="Label" />
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/switchValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="false"
android:theme="@style/menuSwitchTheme"
app:layout_constraintBottom_toBottomOf="@+id/switchTextLabel"
app:layout_constraintStart_toEndOf="@+id/centerRight_line"
app:layout_constraintTop_toTopOf="@+id/switchTextLabel" />
</androidx.constraintlayout.widget.ConstraintLayout>
CustomSwitchCompat.java
public class CustomSwitchCompat extends ConstraintLayout {
private TextView label;
private SwitchCompat switchCompat;
public CustomSwitchCompat(Context context, AttributeSet attrs) {
super(context);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
LayoutInflater.from(context).inflate(R.layout.custom_switch_compat, this, true);
label = findViewById(R.id.switchTextLabel);
switchCompat = findViewById(R.id.switchValue);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CustomSwitchCompat);
String labelText = attributes.getString(R.styleable.CustomSwitchCompat_switchLabelText);
label.setText(labelText);
// Additional attributes such as onText and offText can be set here
attributes.recycle();
}
}
custom_edit_text_compat.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content"
tools:background="@color/black">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerLeft_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.49" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/centerRight_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.51" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/textLabel"
style="@style/ColorAndFontTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="18dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="@+id/centerLeft_line"
app:layout_constraintTop_toTopOf="parent"
tools:text="Label" />
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/editInput"
style="@style/ColorAndFontTheme"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="3dp"
android:textColorHint="@color/gray"
app:layout_constraintBottom_toBottomOf="@+id/textLabel"
app:layout_constraintStart_toStartOf="@+id/centerRight_line"
app:layout_constraintTop_toTopOf="@id/textLabel"
tools:text="Editbox" />
</androidx.constraintlayout.widget.ConstraintLayout>
CustomEditTextCompat.java
public class CustomEditTextCompat extends ConstraintLayout {
protected AppCompatEditText editInput;
private AppCompatTextView textLabel;
public CustomEditTextCompat(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
LayoutInflater.from(context).inflate(R.layout.custom_edit_text_compat, this, true);
textLabel = findViewById(R.id.textLabel);
editInput = findViewById(R.id.editInput);
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.CustomEditTextCompat);
String labelText = attributes.getString(R.styleable.CustomEditTextCompat_labelText);
String hintText = attributes.getString(R.styleable.CustomEditTextCompat_hintText);
textLabel.setText(labelText);
editInput.setHint(hintText);
attributes.recycle();
}
public String getEditTextValue() {
return editInput.getText().toString();
}
public void setLabelText(String text) {
textLabel.setText(text);
}
public void setHintText(String hint) {
editInput.setHint(hint);
}
}
Usage:
<com..menuFragments.components.CustomEditTextCompat
android:id="@+id/custom_attacks_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:hintText="Cool fire wave"
app:labelText="Attack Name"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com..menuFragments.components.CustomSwitchCompat
android:id="@+id/custom_attacks_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/custom_attacks_name"
app:switchLabelText="Finish when done" />
<com..menuFragments.components.CustomEditTextCompat
android:id="@+id/custom_attacks_box_width"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:hintText="Default"
app:labelText="Box width"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/custom_attacks_switch" />
As you state in a comment: "The only strange thing I notice in the layout inspector is that for the CustomSwitchCompat the id is not set, but how could that be possible?" It is a clue that the id is not set.
The id of the view is picked up from the attributes which must be parsed. This is accomplished in one of the ConstraintLayout constructors, namely, public ConstraintLayout(@NonNull Context context, @Nullable AttributeSet attrs).
In your implementation, you don't actually parse out the id directly but expect to leave that work to the super class of ConstraintLayout as stated above. Unfortunately, you call super(context)
and not super(context, attrs)
, so the id (and all other attributes that would be picked up from the attributes are not picked up at all.
Call through to super(context, attrs) to correct your code.