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
Cómo su xml parece? – Jokahero
He actualizado mi pregunta. – Zul
¿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