2012-04-19 7 views
8

¿Cómo hago la configuración de navegación para SwitchReference como la aplicación de configuración nativa de Android?android: Cómo hacer configuraciones de navegación como la aplicación de configuración nativa

Dónde cuando u clic en la región WiFi (no en el interruptor) que navegará a una nueva pantalla:

Click on WiFi

Mi aplicación sólo cambiar el interruptor de encendido a apagado y viceversa, incluso cuando No estoy haciendo clic en el interruptor.

Estoy usando PreferenceFragment y xml para la pantalla. Y mi preferencia es seguir el ejemplo de Android PreferenceFragment documentation. Desarrollo mi aplicación en ICS 4.0 API 14.

¿Alguien sabe cómo hacer esto?

Editado:

Mi aspecto XML como esto:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" > 

    <PreferenceCategory 
     android:layout="@layout/preference_category" 
     android:title="User Settings" > 
     <SwitchPreference 
      android:key="pref_autorun" 
      android:layout="@layout/preference" 
      android:summary="Autorun SMODE on boot" 
      android:title="Autorun SMODE" /> 
     <SwitchPreference 
      android:key="pref_wifi_control" 
      android:layout="@layout/preference" 
      android:selectable="false" 
      android:summary="Controls your Wi-Fi radio automatically based on hotspot availability" 
      android:title="Wi-Fi Radio Control" /> 
    </PreferenceCategory> 
</PreferenceScreen> 
+0

Cómo su xml parece? – Jokahero

+0

He actualizado mi pregunta. – Zul

+0

¿Has encontrado una alternativa más rápida? ¿Solo para determinar cuándo el usuario hizo clic en la casilla de verificación o no? – MatheusJardimB

Respuesta

5

Al echar un vistazo a la fuente de la aplicación de configuración de valores, se puede encontrar cómo lo hicieron.

Básicamente, usan un ArrayAdapter personalizado (al igual que lo haría con un ListView) para mostrar las filas con los botones Cambiar. Y para la segunda pantalla, simplemente usan CustomView disponible en la barra de acciones.

Escribí an article with a sample code para mostrar cómo puede hacerlo en su proyecto. Sin embargo, ten cuidado, esto solo funciona en API Nivel 14 o superior, por lo que si apuntas a dispositivos más antiguos, conserva una pantalla de preferencias de estilo anterior.

+0

Buen trabajo. Eso realmente me ayudó mucho. Gracias Xavier. :) – Zul

+0

Agradable. Habiendo dicho que es ridículo, tienes mucho que codificar para una pantalla de Preferencia simple Y para que funcione para viejas, nuevas y tabletas. Uno debería simplemente declararlo en un archivo xml y DEBERÍA funcionar en todas partes. ¡Período! – powder366

+0

Esta solución parece demasiado grande para un problema tan pequeño.¿Hay alguna alternativa para determinar cuándo el usuario hizo clic en la casilla de verificación o en el área de texto? – MatheusJardimB

1

Veo 2 preguntas aquí: 1. ¿Cómo escuchar las preferencias, haga clic fuera del área del interruptor? 2. ¿Cómo poner un interruptor en la barra de acciones?

voy a responder a la pregunta 1:

he creado una nueva clase SwitchPreference y pesaban más que las onClick método para no hacer nada. Esto evita que la configuración cambie cuando se hace clic fuera del interruptor.

public class SwitchPreference extends android.preference.SwitchPreference { 
    @Override 
    protected void onClick() { 
    } 
} 

Uso (XML):

<android.util.SwitchPreference 
    android:key="whatever" 
    android:title="Whatever" /> 

Uso (Java):

SwitchPreference switchPreference = (SwitchPreference) findPreference("whatever"); 
switchPreference.setOnPreferenceClickListener(new OnPreferenceClickListener() { 
    @Override 
    public boolean onPreferenceClick(Preference preference) { 
     DialogUtils.showToast(Preferences.this, "Clicked outside switch"); 
     return true; 
    } 
}); 
switchPreference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 
    @Override 
    public boolean onPreferenceChange(Preference preference, Object newValue) { 
     DialogUtils.showToast(Preferences.this, "Clicked inside switch and setting changed"); 
     return true; 
    } 
}); 
+0

Me gusta cómo es una respuesta sencilla y bonita, pero cuando probé este código, no se realizó la rama "Cambio de ubicación y cambio de clic hecho clic" incluso si hago clic en la parte del interruptor. – Marc

+0

No funciona en lollipuk. –

1

le dio a este un un intento y ha costado un poco. Pensé que compartiría mi experiencia.

Al principio probé la respuesta por XGouchet ya que tenía la mayoría de los votos. La solución fue bastante complicada y requirió el uso de preference headers que son geniales pero no se ajustaban a lo que estaba haciendo. Decidí que lo más fácil para mí es terminar mi Fragmento de preferencia en un fragmento regular y falsificar la preferencia de cambio con una vista normal.Cavé la fuente de Android para una preferencia y ocurrió esta

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:orientation="vertical" 
tools:context="com.lezyne.link.ui.homeScreen.settingsTab.SettingsFragment"> 

<FrameLayout 
    android:id="@+id/fragment_container" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center_horizontal"> 


</FrameLayout> 

<View 
    android:layout_width="fill_parent" 
    android:layout_height="1dp" 
    android:layout_marginLeft="15dp" 
    android:layout_marginRight="15dp" 
    android:background="#e1e1e1" /> 

<LinearLayout 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:background="?android:attr/selectableItemBackground" 
    android:gravity="center_vertical" 
    android:minHeight="?android:attr/listPreferredItemHeight" 
    android:orientation="horizontal" 
    android:paddingRight="?android:attr/scrollbarSize"> 

    <ImageView 
     android:id="@+id/icon" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="center" /> 

    <RelativeLayout 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_marginBottom="6dip" 
     android:layout_marginLeft="15dip" 
     android:layout_marginRight="6dip" 
     android:layout_marginTop="6dip" 
     android:layout_weight="1"> 

     <TextView 
      android:id="@+id/title" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:ellipsize="marquee" 
      android:fadingEdge="horizontal" 
      android:singleLine="true" 
      android:textAppearance="?android:attr/textAppearanceLarge" /> 

     <TextView 
      android:id="@+id/summary" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignLeft="@android:id/title" 
      android:layout_below="@android:id/title" 
      android:maxLines="4" 
      android:textAppearance="?android:attr/textAppearanceSmall" 
      android:textColor="?android:attr/textColorSecondary" /> 

    </RelativeLayout> 

    <!-- Preference should place its actual preference widget here. --> 
    <RelativeLayout 
     android:id="@+id/widget_frame" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:gravity="center_vertical" 
     android:orientation="vertical" 
     android:paddingEnd="36dp"> 


     <Switch 
      android:thumb="@drawable/switch_inner" 
      android:id="@+id/switch1" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_alignParentEnd="true" /> 

     <TextView 
      android:id="@+id/textView6" 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:layout_marginLeft="2dp" 
      android:text="@string/Notifications" 
      android:textAppearance="?android:attr/textAppearanceMedium" /> 

    </RelativeLayout> 

</LinearLayout> 


<View 
    android:layout_width="fill_parent" 
    android:layout_height="1dp" 
    android:layout_marginLeft="15dp" 
    android:layout_marginRight="15dp" 
    android:background="#e1e1e1" /> 


</LinearLayout> 

El FrameLayout en la parte superior para crear una fragmento de preferencia igual que

getChildFragmentManager() 
      .beginTransaction() 
      .replace(R.id.fragment_container, new SettingsPreferencesFragment(), "SettingsPreferencesFragment") 
      .commit(); 

Entonces puedo conseguir asignar mis clic oyentes como lo haría en cualquier vista regular. SettingsPreferencesFragment es solo un fragmento de preferencia totalmente estándar.

Esta solución parecía bastante buena, pero luego noté problemas de diseño extraños en las tabletas. Me di cuenta de que iba a tener problemas para hacer que esta solución se viera bien en todos los dispositivos y necesitaba usar un conmutador real de referencia no falso.

============== Solución 2 ===============

AlikElzin-kilaka's solution era agradable y simple, pero no funcionó cuando lo intenté Intenté por segunda vez asegurarme de que no lo había hecho mal. Seguí jugando y descubrí algo que parece funcionar. Él tiene un buen punto acerca de

2 preguntas aquí: 1. ¿Cómo se escucha la preferencia, haga clic fuera del área del interruptor ? 2. ¿Cómo poner un interruptor en la barra de acciones?

realmente única pregunta (1) vale la pena responder, porque la pregunta 2 ha sido contestada here y other places

me di cuenta de la única manera de conseguir el acceso a los puntos de vista en una preferencia era crear una clase de niños y anulación onBind. Así que se me ocurrió esta clase secundaria de SwitchPreference que crea manejadores de clics separados para el conmutador como toda la vista. Aún así es un hack.

public class MySwitchPreference extends SwitchPreference { 
public MySwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) { 
    super(context, attrs, defStyleAttr); 
} 


public MySwitchPreference(Context context, AttributeSet attrs) { 
    super(context, attrs); 
    getView(null,null); 

} 

public MySwitchPreference(Context context) { 
    super(context); 
} 

public interface SwitchClickListener{ 
    public void onSwitchClicked(boolean checked); 
    public void onPreferenceClicked(); 
} 
private SwitchClickListener listener = null; 
public void setSwitchClickListener(SwitchClickListener listener){ 
    this.listener = listener; 
} 

public Switch findSwitchWidget(View view){ 
    if (view instanceof Switch){ 
     return (Switch)view; 
    } 
    if (view instanceof ViewGroup){ 
     ViewGroup viewGroup = (ViewGroup)view; 
     for (int i = 0; i < viewGroup.getChildCount();i++){ 
      View child = viewGroup.getChildAt(i); 
      if (child instanceof ViewGroup){ 
       Switch result = findSwitchWidget(child); 
       if (result!=null) return result; 
      } 
      if (child instanceof Switch){ 
       return (Switch)child; 
      } 
     } 
    } 
    return null; 
} 

protected void onBindView (View view){ 
    super.onBindView(view); 

    final Switch switchView = findSwitchWidget(view); 
    if (switchView!=null){ 
     switchView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       if (listener!=null) listener.onSwitchClicked(switchView.isChecked()); 
      } 
     }); 
     switchView.setFocusable(true); 
     switchView.setEnabled(true); 
    } 

    view.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      if (listener!=null) listener.onPreferenceClicked(); 
     } 
    }); 

} 
} 

Utiliza la función recursiva findSwitchWidget para recorrer el árbol hasta que encuentra un interruptor. Me hubiera gustado escribir código como este:

Switch switchView = view.findViewById(android.R.id.switchView); 

pero no parece ser una manera de llegar a ese valor id interna, que yo sepa. De todos modos, una vez que tenemos el cambio real podemos asignarle oyentes y la vista de contenedor. La preferencia de cambio no se actualizará automáticamente, por lo que es necesario guardar la preferencia usted mismo.

MySwitchPreference switchPreference = (MySwitchPreference) findPreference("whatever"); 
    switchPreference.setSwitchClickListener(new MySwitchPreference.SwitchClickListener() { 
     @Override 
     public void onSwitchClicked(boolean checked) { 
      //Save the preference value here 
     } 

     @Override 
     public void onPreferenceClicked() { 
      //Launch the new preference screen or activity here 
     } 
    }); 

Espero que este 2nd hack no vuelva a darme mordiscos.

¿Alguien ve algún riesgo potencial de este método?

También puse una versión ligeramente mejorada del código en GitHub https://gist.github.com/marchold/45e22839eb94aa14dfb5

Cuestiones relacionadas