基于ConstraintLayout的CustomSwitchCompat无法作为约束锚点求助
问题描述
基于ConstraintLayout实现了两个自定义View:CustomEditTextCompat与CustomSwitchCompat,二者实现逻辑基本一致,仅交互组件分别为EditTextCompat和SwitchCompat。当使用CustomEditTextCompat作为layout_constraintTop_toBottomOf的约束锚点时,布局表现正常;但将CustomSwitchCompat作为锚点时,被约束的View会直接跳至顶部。
相关代码如下:
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); } }
使用示例
<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" />
解决方案
问题出在CustomSwitchCompat的构造函数调用上:
- 对比
CustomEditTextCompat的构造函数,它调用了super(context, attrs),而CustomSwitchCompat只调用了super(context),没有传入attrs参数。这会导致自定义View无法正确解析布局中设置的约束属性,进而使得它作为锚点时,后续View的约束计算出错。
修改CustomSwitchCompat的构造函数:
public CustomSwitchCompat(Context context, AttributeSet attrs) { super(context, attrs); // 传入attrs参数 init(context, attrs); }
另外,建议补充实现带三个参数的构造函数,确保在所有场景下布局属性都能正确处理:
public CustomSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); }
修改后,CustomSwitchCompat就能正确参与ConstraintLayout的约束计算,被约束的View也会正常显示在它的下方。
内容的提问来源于stack exchange,提问作者Andreas Andersson
相关产品推荐
相关产品推荐

