ho dato questa una prova e faticato un po '. Ho pensato di condividere la mia esperienza.
All'inizio ho provato la risposta con XGouchet poiché aveva ottenuto i voti migliori. La soluzione era abbastanza complicata e richiesta usando preference headers che sono molto interessanti ma non si adattavano a quello che stavo facendo. Ho deciso che la cosa più facile da fare per me è quella di racchiudere la mia preferenza Frammento in un frammento regolare e rendere falsa la preferenza dell'interruttore con una vista normale.Ho scavato fino alla sorgente di Android per una preferenza e si avvicinò con questo
<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>
Il FrameLayout in alto ottiene un frammento di preferenza in questo modo
getChildFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, new SettingsPreferencesFragment(), "SettingsPreferencesFragment")
.commit();
Poi posso ottenere assegnare i miei click ascoltatori come vorrei in qualsiasi vista normale. SettingsPreferencesFragment è un frammento di preferenza completamente standard.
Questa soluzione sembrava abbastanza buona, ma poi ho notato strani problemi di layout sui tablet. Mi sono reso conto che avrei avuto problemi a trovare questa soluzione in modo corretto su tutti i dispositivi e avevo bisogno di usare un vero switchPreference non falso.
============== Soluzione 2 ===============
AlikElzin-kilaka's solution era bello e semplice, ma non ha funzionato quando ci ho provato Ho provato una seconda volta per assicurarmi di non averlo sbagliato. Ho continuato a giocare e mi è venuto in mente qualcosa che sembra funzionare. Ha una buona opinione su
2 domande qui: 1. Come ascoltare la preferenza clicca all'esterno dell'area di commutazione ? 2. Come inserire un interruttore nella barra delle azioni?
Davvero unica questione (1) vale la pena di rispondere, perché la domanda 2 è stato risposto here e other places
ho capito l'unico modo per ottenere l'accesso alle viste di una preferenza era quella di creare una classe figlia e di override onBind. Così mi è venuta in mente questa classe figlia di SwitchPreference che crea gestori di clic separati per lo switch come l'intera vista. Comunque è ancora 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();
}
});
}
}
Utilizza la funzione ricorsiva findSwitchWidget per percorrere l'albero finché non trova un interruttore. Avrei preferito scrivere codice come questo:
Switch switchView = view.findViewById(android.R.id.switchView);
, ma non sembra essere un modo per arrivare a quel valore ID interno, che io sappia. In ogni caso, una volta ottenuto il passaggio effettivo, possiamo assegnare gli ascoltatori e la vista del contenitore. La preferenza dello switch non si aggiornerà automaticamente, quindi è necessario salvarla autonomamente.
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
}
});
Speriamo che questa seconda modifica non ritorni a mordermi.
Qualcuno vede qualche potenziale insidia di questo metodo?
ho anche messo una versione leggermente migliorata del codice su GitHub https://gist.github.com/marchold/45e22839eb94aa14dfb5
Come il tuo XML assomiglia? – Jokahero
Ho aggiornato la mia domanda. – Zul
Hai trovato un'alternativa più rapida? Solo per determinare quando l'utente ha fatto clic sulla casella di controllo o no? – MatheusJardimB