自定义视图中 child 个视图的 ID 在 Android 中相同
ID of the child views in a custom view are same in Android
我有一个自定义视图 ValueSelectorView
,其中包含两个用于递增和递减值的按钮以及一个用于显示该值的 EditText。在我的 activity 中,我使用了这个视图 3 次。我在这里担心的是 child 观点,即他们的 id
在日志中检查时总是相同的。因此,结果值不正确。
我查看了 Whosebug,发现他们中的一些人遇到了同样的问题,他们正试图通过使用 setId
手动更改 child 视图的 ID 来解决这个问题。尝试使用几种不同的方法膨胀 child 视图,但问题仍然存在
这是我的自定义视图class
package eu.siacs.conversations.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
public class ValueSelectorView extends RelativeLayout {
View rootView;
EditText valueTextView;
View minusButton;
View plusButton;
private int minValue = Integer.MIN_VALUE;
private int maxValue = Integer.MAX_VALUE;
public ValueSelectorView(Context context) {
super(context);
init(context, null);
}
public ValueSelectorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
rootView = LayoutInflater.from(context).inflate(R.layout.value_selector, this, true);
Log.i(Config.LOGTAG, "****view testr**** id of this view is -->" + getResources().getResourceEntryName(rootView.getId()));
valueTextView = rootView.findViewById(R.id.valueTextView);
minusButton = rootView.findViewById(R.id.minusButton);
plusButton = rootView.findViewById(R.id.plusButton);
minusButton.setOnClickListener(v -> decrementValue());
plusButton.setOnClickListener(v -> incrementValue());
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ValueSelectorView,0,0);
int defaultVaue = typedArray.getInt(R.styleable.ValueSelectorView_defaultValue,0);
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 0 -->" + valueTextView.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Minus Button is 0 -->" + minusButton.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Add Button is 0 -->" + plusButton.getId());
valueTextView.setText(String.valueOf(defaultVaue));
typedArray.recycle();
}
public void setDefaultValue(int value) {
valueTextView.setText(String.valueOf(value));
}
public int getMinValue() {
return minValue;
}
public void setMinValue(int minValue) {
this.minValue = minValue;
}
public int getMaxValue() {
return maxValue;
}
public void setMaxValue(int maxValue) {
this.maxValue = maxValue;
}
public int getValue() {
return Integer.valueOf(valueTextView.getText().toString());
}
/*public void setValue(int newValue) {
int value = newValue;
if(newValue < minValue) {
value = minValue;
} else if (newValue > maxValue) {
value = maxValue;
}
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 1 -->" + valueTextView.getId());
valueTextView.setText(String.valueOf(value));
}*/
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
}
private void incrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal < maxValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 2-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal + 1));
}
}
private void decrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal > minValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 3-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal - 1));
}
}
}
这就是我在 activity XML.
中使用它的方式
<eu.siacs.conversations.ui.widget.ValueSelectorView
android:id="@+id/value_selector_nights"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin4"
app:defaultValue="1"
android:gravity="center_vertical"/>
<eu.siacs.conversations.ui.widget.ValueSelectorView
android:id="@+id/value_selector_adults"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin4"
app:defaultValue="1"
android:gravity="center_vertical"/>
<eu.siacs.conversations.ui.widget.ValueSelectorView
android:id="@+id/value_selector_children"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:defaultValue="0"
android:layout_marginTop="@dimen/margin4"
android:gravity="center_vertical"/>
以下是日志:
****view testr**** id of this view is -->value_selector_nights
****view testr**** id of this TextView is 0 -->2131297384
****view testr**** id of this view is -->value_selector_adults
****view testr**** id of this TextView is 0 -->2131297384
****view testr**** id of this view is -->value_selector_children
****view testr**** id of this TextView is 0 -->2131297384
我想了解它的内部工作原理并找到解决方案。谢谢你的时间。
对于面临同样问题的其他人。
我更新的代码是:
package eu.siacs.conversations.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
public class ValueSelectorView extends RelativeLayout {
View rootView;
EditText valueTextView;
View minusButton;
View plusButton;
private int customState;
private int minValue = Integer.MIN_VALUE;
private int maxValue = Integer.MAX_VALUE;
public ValueSelectorView(Context context) {
super(context);
init(context, null);
}
public ValueSelectorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
rootView = LayoutInflater.from(context).inflate(R.layout.value_selector, this, true);
Log.i(Config.LOGTAG, "****view testr**** id of this view is -->" + getResources().getResourceEntryName(rootView.getId()));
valueTextView = rootView.findViewById(R.id.valueTextView);
minusButton = rootView.findViewById(R.id.minusButton);
plusButton = rootView.findViewById(R.id.plusButton);
minusButton.setOnClickListener(v -> decrementValue());
plusButton.setOnClickListener(v -> incrementValue());
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ValueSelectorView,0,0);
int defaultVaue = typedArray.getInt(R.styleable.ValueSelectorView_defaultValue,0);
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 0 -->" + valueTextView.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Minus Button is 0 -->" + minusButton.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Add Button is 0 -->" + plusButton.getId());
valueTextView.setText(String.valueOf(defaultVaue));
typedArray.recycle();
}
public void setDefaultValue(int value) {
valueTextView.setText(String.valueOf(value));
}
public int getMinValue() {
return minValue;
}
public void setMinValue(int minValue) {
this.minValue = minValue;
}
public int getMaxValue() {
return maxValue;
}
public void setMaxValue(int maxValue) {
this.maxValue = maxValue;
}
public int getValue() {
return Integer.valueOf(valueTextView.getText().toString());
}
/*public void setValue(int newValue) {
int value = newValue;
if(newValue < minValue) {
value = minValue;
} else if (newValue > maxValue) {
value = maxValue;
}
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 1 -->" + valueTextView.getId());
valueTextView.setText(String.valueOf(value));
}*/
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
}
private void incrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal < maxValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 2-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal + 1));
}
}
private void decrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal > minValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 3-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal - 1));
}
}
public void setCustomState(int customState) {
this.customState = customState;
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.value = valueTextView.getText().toString();
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
valueTextView.setText(ss.value);
}
public static class SavedState extends BaseSavedState {
String value;
SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
我的自定义视图中的子视图 XML
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/medium_font"
android:enabled="false"
android:background="@null"
android:textColor="#000000"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/minusButton"
android:saveEnabled="false"
android:id="@+id/valueTextView" />
我有一个自定义视图 ValueSelectorView
,其中包含两个用于递增和递减值的按钮以及一个用于显示该值的 EditText。在我的 activity 中,我使用了这个视图 3 次。我在这里担心的是 child 观点,即他们的 id
在日志中检查时总是相同的。因此,结果值不正确。
我查看了 Whosebug,发现他们中的一些人遇到了同样的问题,他们正试图通过使用 setId
手动更改 child 视图的 ID 来解决这个问题。尝试使用几种不同的方法膨胀 child 视图,但问题仍然存在
这是我的自定义视图class
package eu.siacs.conversations.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.RequiresApi;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
public class ValueSelectorView extends RelativeLayout {
View rootView;
EditText valueTextView;
View minusButton;
View plusButton;
private int minValue = Integer.MIN_VALUE;
private int maxValue = Integer.MAX_VALUE;
public ValueSelectorView(Context context) {
super(context);
init(context, null);
}
public ValueSelectorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
rootView = LayoutInflater.from(context).inflate(R.layout.value_selector, this, true);
Log.i(Config.LOGTAG, "****view testr**** id of this view is -->" + getResources().getResourceEntryName(rootView.getId()));
valueTextView = rootView.findViewById(R.id.valueTextView);
minusButton = rootView.findViewById(R.id.minusButton);
plusButton = rootView.findViewById(R.id.plusButton);
minusButton.setOnClickListener(v -> decrementValue());
plusButton.setOnClickListener(v -> incrementValue());
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ValueSelectorView,0,0);
int defaultVaue = typedArray.getInt(R.styleable.ValueSelectorView_defaultValue,0);
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 0 -->" + valueTextView.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Minus Button is 0 -->" + minusButton.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Add Button is 0 -->" + plusButton.getId());
valueTextView.setText(String.valueOf(defaultVaue));
typedArray.recycle();
}
public void setDefaultValue(int value) {
valueTextView.setText(String.valueOf(value));
}
public int getMinValue() {
return minValue;
}
public void setMinValue(int minValue) {
this.minValue = minValue;
}
public int getMaxValue() {
return maxValue;
}
public void setMaxValue(int maxValue) {
this.maxValue = maxValue;
}
public int getValue() {
return Integer.valueOf(valueTextView.getText().toString());
}
/*public void setValue(int newValue) {
int value = newValue;
if(newValue < minValue) {
value = minValue;
} else if (newValue > maxValue) {
value = maxValue;
}
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 1 -->" + valueTextView.getId());
valueTextView.setText(String.valueOf(value));
}*/
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
}
private void incrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal < maxValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 2-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal + 1));
}
}
private void decrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal > minValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 3-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal - 1));
}
}
}
这就是我在 activity XML.
中使用它的方式<eu.siacs.conversations.ui.widget.ValueSelectorView
android:id="@+id/value_selector_nights"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin4"
app:defaultValue="1"
android:gravity="center_vertical"/>
<eu.siacs.conversations.ui.widget.ValueSelectorView
android:id="@+id/value_selector_adults"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin4"
app:defaultValue="1"
android:gravity="center_vertical"/>
<eu.siacs.conversations.ui.widget.ValueSelectorView
android:id="@+id/value_selector_children"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:defaultValue="0"
android:layout_marginTop="@dimen/margin4"
android:gravity="center_vertical"/>
以下是日志:
****view testr**** id of this view is -->value_selector_nights
****view testr**** id of this TextView is 0 -->2131297384
****view testr**** id of this view is -->value_selector_adults
****view testr**** id of this TextView is 0 -->2131297384
****view testr**** id of this view is -->value_selector_children
****view testr**** id of this TextView is 0 -->2131297384
我想了解它的内部工作原理并找到解决方案。谢谢你的时间。
对于面临同样问题的其他人。
我更新的代码是:
package eu.siacs.conversations.ui.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
public class ValueSelectorView extends RelativeLayout {
View rootView;
EditText valueTextView;
View minusButton;
View plusButton;
private int customState;
private int minValue = Integer.MIN_VALUE;
private int maxValue = Integer.MAX_VALUE;
public ValueSelectorView(Context context) {
super(context);
init(context, null);
}
public ValueSelectorView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ValueSelectorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
rootView = LayoutInflater.from(context).inflate(R.layout.value_selector, this, true);
Log.i(Config.LOGTAG, "****view testr**** id of this view is -->" + getResources().getResourceEntryName(rootView.getId()));
valueTextView = rootView.findViewById(R.id.valueTextView);
minusButton = rootView.findViewById(R.id.minusButton);
plusButton = rootView.findViewById(R.id.plusButton);
minusButton.setOnClickListener(v -> decrementValue());
plusButton.setOnClickListener(v -> incrementValue());
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ValueSelectorView,0,0);
int defaultVaue = typedArray.getInt(R.styleable.ValueSelectorView_defaultValue,0);
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 0 -->" + valueTextView.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Minus Button is 0 -->" + minusButton.getId());
// Log.i(Config.LOGTAG, "****view testr**** id of this Add Button is 0 -->" + plusButton.getId());
valueTextView.setText(String.valueOf(defaultVaue));
typedArray.recycle();
}
public void setDefaultValue(int value) {
valueTextView.setText(String.valueOf(value));
}
public int getMinValue() {
return minValue;
}
public void setMinValue(int minValue) {
this.minValue = minValue;
}
public int getMaxValue() {
return maxValue;
}
public void setMaxValue(int maxValue) {
this.maxValue = maxValue;
}
public int getValue() {
return Integer.valueOf(valueTextView.getText().toString());
}
/*public void setValue(int newValue) {
int value = newValue;
if(newValue < minValue) {
value = minValue;
} else if (newValue > maxValue) {
value = maxValue;
}
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 1 -->" + valueTextView.getId());
valueTextView.setText(String.valueOf(value));
}*/
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
}
private void incrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal < maxValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 2-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal + 1));
}
}
private void decrementValue() {
int currentVal = Integer.valueOf(valueTextView.getText().toString());
if(currentVal > minValue) {
Log.i(Config.LOGTAG, "****view testr**** id of this TextView is 3-->" + valueTextView.getId());
valueTextView.setText(String.valueOf(currentVal - 1));
}
}
public void setCustomState(int customState) {
this.customState = customState;
}
@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.value = valueTextView.getText().toString();
return ss;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
valueTextView.setText(ss.value);
}
public static class SavedState extends BaseSavedState {
String value;
SavedState(Parcelable superState) {
super(superState);
}
public SavedState(Parcel source) {
super(source);
value = source.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(value);
}
public static final Parcelable.Creator<SavedState> CREATOR =
new Parcelable.Creator<SavedState>() {
public SavedState createFromParcel(Parcel in) {
return new SavedState(in);
}
public SavedState[] newArray(int size) {
return new SavedState[size];
}
};
}
}
我的自定义视图中的子视图 XML
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/medium_font"
android:enabled="false"
android:background="@null"
android:textColor="#000000"
android:layout_centerVertical="true"
android:layout_toRightOf="@id/minusButton"
android:saveEnabled="false"
android:id="@+id/valueTextView" />