3

I need to create custom view - TextView and Switch button.

I have custom view:

public class CustomTextWithSwitch extends LinearLayout implements View.OnClickListener {

  private CustomTextWithSwitchBinding binding;
  private boolean defaultValue;

  public CustomTextWithSwitch(Context context) {
      this(context, null);
  }

  public CustomTextWithSwitch(Context context, @Nullable AttributeSet attrs) {
      this(context, attrs, 0);
  }

  public CustomTextWithSwitch(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      binding = CustomTextWithSwitchBinding.inflate(LayoutInflater.from(getContext()), this);
      TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CustomTextWithSwitch);
      defaultValue = a.getBoolean(R.styleable.CustomTextWithSwitch_defaultValue, false);
      a.recycle();
  }

  @Override
  protected void onFinishInflate() {
      ...
      binding.sToggle.setChecked(defaultValue);
      super.setOnClickListener(this);

      super.onFinishInflate();
  }

  public void toggle() {
      binding.sToggle.toggle();
      defaultValue = binding.sToggle.isChecked();
  }

  @Override
  public void onClick(View view) {
      toggle();
  }

  public void setDefaultValue(boolean defaultValue) {
      this.defaultValue = defaultValue;
      binding.sToggle.setChecked(defaultValue);
    }
}

I use that in the activity:

public class MyActivity extends AppCompatActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      ...
      myCustomView.setDefaultValue(true);
  }
}

When I open this activity, everything works as expected - switch button is checked. However, when I rotate the screen, it is checked to false. Can somebody advise what am I doing incorrectly? Note: I use ViewModel and the value is restored correctly. However, the Switch button in this custom view is not toggled.

UPDATE: This issue happens only when I have another CustomTextWithSwich in my activity, so it means they have effect on each other(it seems that default value is set according to second View). Is it possible to separate them, so they are standalone?

Tom11
  • 2,419
  • 8
  • 30
  • 56

3 Answers3

0

I suggest you to use a ViewModdel. During rotation it is normal that you will lost the states. ViewModel will not be destroyed during app rotation so the last state of CustomTextWithSwich will be not lost.

On the other hand you can override onConfigurationChanged method every time app is rotated this method will run, so you can use it to set your data.

    @Override
    public void onConfigurationChanged(@NonNull Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }
Mustafa Ozhan
  • 321
  • 6
  • 9
  • I am using `ViewModel`. The value is restored on configuration change, but `Switch` button is not toggled. – Tom11 Aug 03 '20 at 06:31
  • @Tom11 Did you try to set status of `Switch` in `onConfigurationChanged` method reading from `ViewModel` ? – Mustafa Ozhan Aug 03 '20 at 11:40
  • Yes, still the same issue. – Tom11 Aug 03 '20 at 16:47
  • @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); myCustomView.setDefaultValue(viewModel.isSwitchChecked); } // You need too use like this – Mustafa Ozhan Aug 03 '20 at 19:32
0

Please check whether both of your CustomTextWithSwitch and its children on Activity has android:ids. Ids should be different. In this case Android take care about saving instance state for your view.

If it does not save your state, use this code inside your CustomTextWithSwitch

@Override
  public Parcelable onSaveInstanceState()
  {
    Bundle bundle = new Bundle();
    bundle.putParcelable("superState", super.onSaveInstanceState());
    bundle.putBoolean("isChecked", defaultValue); // ... save check state 
    return bundle;
  }

  @Override
  public void onRestoreInstanceState(Parcelable state)
  {
    if (state instanceof Bundle)
    {
      Bundle bundle = (Bundle) state;
      defaultValue = bundle.getBoolean("isChecked"); // ... load state
      binding.sToggle.setChecked(defaultValue);
      state = bundle.getParcelable("superState");
    }
    super.onRestoreInstanceState(state);
  }
anil
  • 2,083
  • 21
  • 37
  • I use IDs. The problem is, that it saves instance state, but do not toggle `Switch` button. – Tom11 Aug 03 '20 at 06:30
0

Have faced the same issue. I fixed it by setting setSaveEnabled(false) on the switch view. Just let the viewModel restore it's state.

public CustomTextWithSwitch(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      binding = CustomTextWithSwitchBinding.inflate(LayoutInflater.from(getContext()), this);
      TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CustomTextWithSwitch);
      defaultValue = a.getBoolean(R.styleable.CustomTextWithSwitch_defaultValue, false);
      a.recycle();

    //Add this (assuming your switch view id is 'switch_view')
    binding.switchView.setSaveEnabled(false);
}
ltp
  • 366
  • 3
  • 10