6

Mam widoku niestandardowego, powiedzmy, że to jest jego kod:przywracania stanu widoku przed zastosowaniem XML atrybuty

public class CustomView extends View { 

    boolean visible; 
    boolean enabled; 

    public ScheduleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 

     TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView, 0, 0); 
     try { 
      visible = a.getBoolean(R.styleable.CustomView_visible, true); 
      enabled = a.getBoolean(R.styleable.CustomView_enabled, true); 
     } finally { 
      a.recycle(); 
     } 

     // Apply XML attributes here 
    } 

    @Override 
    public Parcelable onSaveInstanceState() { 
     // Save instance state 
     Bundle bundle = new Bundle(); 
     bundle.putParcelable("superState", super.onSaveInstanceState()); 
     bundle.putBoolean("visible", visible); 
     bundle.putBoolean("enabled", enabled); 

     return bundle; 
    } 

    @Override 
    public void onRestoreInstanceState(Parcelable state) { 
     // Restore instance state 
     // This is called after constructor 
     if (state instanceof Bundle) { 
      Bundle bundle = (Bundle) state; 
      visible = bundle.getBoolean("visible"); 
      enabled = bundle.getBoolean("enabled"); 

      state = bundle.getParcelable("superState"); 
     } 
     super.onRestoreInstanceState(state); 
    } 
} 

całkiem proste. Mój widok niestandardowy odczytuje atrybuty z XML i je stosuje. Atrybuty te są zapisywane i odtwarzane po zmianie konfiguracji.

Ale jeśli mam, dla dwóch różnych orientacjach dwa inny układ na przykład:

[layout-port/view.xml] 
<CustomView 
    custom:visible="true" 
    custom:enabled="true" 

[layout-land/view.xml] 
<CustomView 
    custom:visible="false" 
    custom:enabled="false" 

Moim problemem jest to, że przy zmianie orientacji urządzenia, widok stan jest zapisywany jako widoczne i włączone, ale teraz stany układu XML widok też nie powinien. Konstruktor zostaje wywołany przed onRestoreInstanceState, a atrybuty XML zostają nadpisane przez zapisany stan. Nie chcę tego, XML ma pierwszeństwo przed stanem zapisanym.

Robię coś nie tak? Jaki byłby najlepszy sposób rozwiązania tego problemu?

+0

przechowywania wartości xml w innych zmiennych i ponownie je po renowacji. Możesz także nie stosować przywracania, więc wartości zawsze będą tymi zdefiniowanymi w xml – nandsito

+0

@nandsito Prawdopodobnie to właśnie robię. Po prostu pomyślałem, że może jest bardziej bezpośredni sposób na zrobienie tego, sposób na przywrócenie stanu po analizie XML. Myślałem, że mogę to zrobić, aby zapisać AttributeSet do zmiennej, a następnie przeanalizować XML na końcu onRestoreInstanteState. Ale jest onRestoreInstanteState nie jest wywoływana, gdy widok jest tworzony po raz pierwszy. –

+0

Android analizuje xml i stosuje jego atrybuty w konstruktorze widoku, więc xml jest zawsze przetwarzany przed stanem przywracania. Jeśli chcesz zmienić tę kolejność, musisz ręcznie ustawić wartości zmiennych. – nandsito

Odpowiedz

0

W twoim przypadku musisz zapisać aktualną orientację w Parcelable wraz z innymi atrybutami i zastosować te przywrócone atrybuty tylko w przypadku, gdy przywrócona orientacja jest równa aktualnej orientacji (tj. Aktywność została zniszczona i przywrócona przez system operacyjny). W twoim przypadku użyłbym android:tag do określenia orientacji obecną tak:

[layout-port/view.xml] 
<CustomView 
    android:tag="port" 
    custom:visible="true" 
    custom:enabled="true" 

[layout-land/view.xml] 
<CustomView 
    android:tag="land" 
    custom:visible="false" 
    custom:enabled="false" 

A potem widoku niestandardowego klasa będzie jak:

public class ScheduleView extends View { 

    String orientation; 
    boolean visible; 
    boolean enabled; 

    public ScheduleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 

     TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView, 0, 0); 
     try { 
      visible = a.getBoolean(R.styleable.CustomView_visible, true); 
      enabled = a.getBoolean(R.styleable.CustomView_enabled, true); 
     } finally { 
      a.recycle(); 
     } 

     orientation = (String) getTag(); 
    } 

    @Override 
    public Parcelable onSaveInstanceState() { 
     // Save instance state 
     Bundle bundle = new Bundle(); 
     bundle.putParcelable("superState", super.onSaveInstanceState()); 
     bundle.putBoolean("visible", visible); 
     bundle.putBoolean("enabled", enabled); 
     bundle.putString("orientation", orientation); 

     return bundle; 
    } 

    @Override 
    public void onRestoreInstanceState(Parcelable state) { 
     // Restore instance state 
     // This is called after constructor 
     if (state instanceof Bundle) { 
      Bundle bundle = (Bundle) state; 

      String restoredOrientation = bundle.getString("orientation"); 
      if (restoredOrientation.equals(orientation)) { 
       visible = bundle.getBoolean("visible"); 
       enabled = bundle.getBoolean("enabled"); 
      } 

      state = bundle.getParcelable("superState"); 
     } 
     super.onRestoreInstanceState(state); 
    } 
} 

nie testowałem go poprawnie, ale to powinno działać. Mam nadzieję, że będzie to pomocne.

+0

Chcę zastosować niektóre zapisane atrybuty, które nie są w formacie XML. To samo dotyczy odpowiedzi Azizbekian. –

+0

Przepraszam, ale nie mam problemu. Właściwie możesz zastosować te atrybuty spoza xml poza blokiem 'if' w metodzie' onRestoreInstanceState'. – rom4ek

+0

'onRestoreInstanceState' nie zawsze jest nazywane, to jest problem. –

0

Zasadniczo konieczne jest rozdzielenie stanów na pionowe i poziome, co oznacza, że ​​należy również zapisać określony stan konfiguracji.

final boolean isPortrait = 
      getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 
bundle.putBoolean("isPortrait", isPortrait); 

Następnie podczas przywracania stanu:

final boolean savedOrientation = bundle.getBoolean("isPortrait"); 
final boolean currentOrientation = 
      getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 

if (savedOrientation == currentOrientation) { 
    // now retrieve saved values 
} else { 
    // do nothing, values are initialized in constructor 
} 
Powiązane problemy