ID of the child views in a custom view are same in Android

ⅰ亾dé卋堺 提交于 2020-01-01 19:23:17

问题


I have a custom view ValueSelectorView which contains two buttons to increment and decrement value and an EditText to display that value. In my activity, I am using this view three times. My concern here is with the child views that their id is always the same when checked in logs. Due to this, the resultant value comes out to be incorrect.

I have looked over on StackOverflow and found out that some of them have faced the same issue and they are trying to solve it by manually altering the id of the child views using setId. Tried inflating the child views using a couple of different methods but the issue still persists

This is my custom view 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));
        }
    }


}

This is how I use it in my 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"/>

Below are the logs:

****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

I would like to understand how it works internally and find a solution for the same. Thank you for your time.


回答1:


For others, who are facing the same issue.

My updated code is:

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];
                    }
                };
    }
}

Child view XML in my custom view

<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" />


来源:https://stackoverflow.com/questions/57533532/id-of-the-child-views-in-a-custom-view-are-same-in-android

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!