From 401af2b4a5b2b282c85a146fab3b6e65e2bbc8b6 Mon Sep 17 00:00:00 2001 From: Matt Date: Wed, 15 Jan 2020 22:39:08 +1300 Subject: [PATCH 1/3] Dynamic category expand/collapse --- .../demo/MyPreferenceFragment.java | 33 ++ app/src/main/res/xml/settings.xml | 38 ++- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- .../preferencex/PreferenceShowHide.java | 285 ++++++++++++++++++ 5 files changed, 343 insertions(+), 19 deletions(-) create mode 100644 preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java diff --git a/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java b/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java index 6570f6c..d637493 100644 --- a/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java +++ b/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java @@ -2,24 +2,39 @@ import android.content.Context; import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.ViewGroup; import com.takisoft.preferencex.PreferenceFragmentCompat; +import com.takisoft.preferencex.PreferenceShowHide; import androidx.annotation.Nullable; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; +import androidx.recyclerview.widget.RecyclerView; /** * A placeholder fragment containing a simple view. + * Also illustrates optional deployment of {@link PreferenceShowHide} which allows for + * expansion/collapse via 'tap' of PreferenceCategory title. */ public class MyPreferenceFragment extends PreferenceFragmentCompat { + PreferenceShowHide showHide; + RecyclerView RV; + @Override public void onCreatePreferencesFix(@Nullable Bundle savedInstanceState, String rootKey) { setPreferencesFromResource(R.xml.settings, rootKey); testDynamicPrefs(); + // Collapse the UI so the user sees only the PreferenceCategory titles. + // Tapping the title toggles visibility of the actual Preferences. + // Exception: If PreferenceCategory title 'isEmpty()' children are not hidden. + showHide = new PreferenceShowHide(this, null, true); + Preference prefEmptyCheck = findPreference("pref_empty_check"); if (prefEmptyCheck != null) { @@ -63,4 +78,22 @@ public boolean onPreferenceClick(Preference preference) { }); } } + + /** Supply the RecyclerView. NB: Indirectly called by onCreateView()
+ NB: This is required only for deployment of {@link PreferenceShowHide} */ + @Override public RecyclerView onCreateRecyclerView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { + RV = super.onCreateRecyclerView(inflater, parent, savedInstanceState); + if (RV!=null) { // Probably default: R.id.recycler_view + Log.d("onCreateRecyclerView", "Default RecyclerView located"); + showHide.setRecyclerView(RV); + RV.setLayoutManager(onCreateLayoutManager()); + return RV; + } + Log.d("onCreateRecyclerView", "Could not supply default RecyclerView to 'ShowHide' helper!"); + // If you are using a custom layout you must still provide the RecyclerView ... + // ... For example: parent.findViewById(R.id.myRecyclerView) + Log.d("onCreateRecyclerView", "See also: themes.xml 'PreferenceThemeOverlay'"); + return RV; + } + } diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index bfa82d0..c422ccd 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -1,7 +1,9 @@ - - + - - - + + - - - - - - - - PreferenceCategory by tapping it's title ...
+
    Edit your sub-classed PreferenceFragmentCompat as follows:
+
  • Instantiate this class in onCreatePreferencesFix()
  • +
  • Supply RecyclerView by overriding onCreateRecyclerView()
  • + Refer to the sample app {@link com.takisoft.preferencex.demo.MyPreferenceFragment}
    +
      Additionally ... +
    • Your PreferenceScreen must have a key (eg: "root")
    • +
    • Every PreferenceCategory AND Preference will ideally have a unique key
    • +
    • Every PreferenceCategory probably should have a title. (Otherwise there is nothing for the user to + tap and thereby toggle child Preference visibility)
    • +
    • If a PreferenceCategory has an empty title it's children will not be hidden.
    • +
    • If a child Preference has no key, one will be assigned.
    • +
    • Keys are generally required for internal use by this program but vital should your + application wish to display only a specific PreferenceCategory or Preference.
    • +
    */ +public class PreferenceShowHide { + PreferenceFragmentCompat pfc; // References to caller + private String root; // PreferenceScreen name. + public String getRoot() { return root; } + private String specPref; // Named PreferenceCategory or Preference + public String getSpecPref() { return specPref; } + private boolean specific; // Handy flag for above + public boolean isSpecific(){ return specific; }; + private boolean debug; // Request/suppress logging + private RecyclerView RV = null; + /** User responsibility to supply RecyclerView! See 'onCreateRecyclerView()' */ + public void setRecyclerView(RecyclerView recyclerView) { + if (!isInitOK()) return; + RV = recyclerView; + OITL = new RecyclerItemClickListener(pfc.getContext(), new CategoryListener() { + @Override + public void onItemClick(View view, int position) { clicked(view, position); } + }); + if (RV!=null) RV.addOnItemTouchListener(OITL); + } + private List categories = new ArrayList<>(); + private List collapsed = new ArrayList<>(); + private List preferences = new ArrayList<>(); + public String lastLogged; + private boolean initOK; + public boolean isInitOK() { return initOK; } + private boolean scroll=true; + public void setScroll(boolean scroll) { this.scroll = scroll; } + + /** Constructor. (Caller may issue isInitOK() to test for success.) + @param pfc Your PreferenceFragmentCompat + @param specPref Key of specific PreferenceCategory OR specific Preference OR null/empty + @param debug true: log messages + @see #removeAllButPreviouslySpecifiedPreference() + @see #isInitOK() */ + public PreferenceShowHide(PreferenceFragmentCompat pfc, String specPref, boolean debug) { + this.pfc = pfc; + this.specPref = specPref; + specific = !(specPref==null || specPref.isEmpty()); + this.debug = debug; + initOK = analyzeXML(); + } + + /** Analyze XML / Collapse all categories. + @return false Exception described in 'lastLogged' */ + private boolean analyzeXML() { + PreferenceScreen ps = pfc.getPreferenceScreen(); + root = ps.getKey(); + if (root==null || root.isEmpty()) { + logFatal("PreferenceScreen has null or empty key. Please repair"); + return false; + } + + int generated = 0; + for (int i=0; i0) { log(format("%d Preference(s) without keys", generated)); } + return true; + } + + /** Toggle visibility of all children in the category */ + @SuppressLint("RestrictedApi") + private void clicked(View v, int position) { + Preference pref = ((PreferenceGroupAdapter) RV.getAdapter()).getItem(position); + if (!(pref instanceof PreferenceCategory)) return; + String cat = pref.getKey(); + int ix = categories.indexOf(cat); + log(format("Clicked category '%s' [%d] collapsed=%b", cat, ix, collapsed.get(ix))); + for (String key : preferences.get(ix)) { + pfc.findPreference(key).setVisible(collapsed.get(ix)); + } + collapsed.set(ix, !(collapsed.get(ix))); + if (collapsed.get(ix)) return; + + // Smoothly scroll tapped category to top of screen at 1/4 speed + if (scroll) scroll(RV, position); + + } + + //---------------------------------------------------------------------------------------------- + /** Gets called for every single preference [Experiment] */ + private void everySinglePreference(Preference pref) { + if (true) return; + if (pref instanceof EditTextPreference) { + EditTextPreference etp = (EditTextPreference) pref; + etp.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() { + @Override + public void onBindEditText(@NonNull EditText editText) { + // So what! Doesn't tell me what the XML EditTextPreference inputType was! + } + }); + } + } + + //---------------------------------------------------------------------------------------------- + + /** Remove all preferences except the one specified during construction.
    + If that was a PreferenceCategory retain visibility of the entire category.
    + Tip: Call this from your PreferenceFragmentCompat 'onStart()' override. */ + @SuppressLint("RestrictedApi") + public void removeAllButPreviouslySpecifiedPreference() { + if (!isInitOK()) return; + Preference keepPref = pfc.findPreference(specPref); + if (keepPref == null || RV == null) { return;} + PreferenceGroup keepParent = getParent(keepPref); + boolean keepCategory = (root.equals(keepParent.getKey())); + log(format("Removing all preferences except '%s/%s'", keepParent.getKey(), specPref)); + for (int i = 0; i < RV.getAdapter().getItemCount(); i++) { + Preference pref = ((PreferenceGroupAdapter) RV.getAdapter()).getItem(i); + PreferenceGroup parent = getParent(pref); + if (parent == null) continue; // Already deleted! + if (keepCategory) { + if (pref.getKey().equals(specPref)) continue; + if (parent.getKey().equals(specPref)) continue; + } else { + if(pref.getKey().equals(keepParent.getKey()) || pref.getKey().equals(specPref)) continue; + } + boolean rc = parent.removePreference(pref); // NB: If a parent, children go also! + log(format("removePreference(%s/%s)=%b", parent.getKey(), pref.getKey(), rc)); + } + log(format("remaining=%d", RV.getAdapter().getItemCount())); + } + + // Obtain the parent of a Preference [ PreferenceScreen OR PreferenceCategory ] + private PreferenceGroup getParent(Preference pref) { + return getParent(pfc.getPreferenceScreen(), pref); + } + private PreferenceGroup getParent(PreferenceGroup root, Preference pref) { + for (int i = 0; i < root.getPreferenceCount(); i++) { + Preference p = root.getPreference(i); + if (p == pref) return root; + if (PreferenceGroup.class.isInstance(p)) { + PreferenceGroup parent = getParent((PreferenceGroup)p, pref); + if (parent != null) return parent; + } + } + log("Could not find parent for " + pref.getKey()); + return null; + } + + // --------------------------------------------------------------------------------------------- + /** Smoothly scroll to specified position at 1/4 speed
    + Extremely primitive but OK for short things like Preferences */ + private void scroll(RecyclerView rv, int position) throws IllegalArgumentException { + RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(pfc.getContext()) { + @Override protected int getVerticalSnapPreference() { + return LinearSmoothScroller.SNAP_TO_START; + } + @Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { + float millesecondsPerPixel = super.calculateSpeedPerPixel(displayMetrics); + return millesecondsPerPixel * 4; + } + }; + smoothScroller.setTargetPosition(position); + rv.getLayoutManager().startSmoothScroll(smoothScroller); + } + + // --------------------------------------------------------------------------------------------- + + /** Click listener reacting to PreferenceCategory */ + RecyclerView.OnItemTouchListener OITL; + + /** Custom RecyclerView touch listener. */ + public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener { + private CategoryListener mListener; + GestureDetector mGestureDetector; + /** Constructor is supplied the callback for PreferenceCategory interception! */ + public RecyclerItemClickListener(Context context, CategoryListener listener) { + mListener = listener; + mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + return true; + } + }); + } + @Override + public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { + View childView = view.findChildViewUnder(e.getX(), e.getY()); + if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) { + mListener.onItemClick(childView, view.getChildAdapterPosition(childView)); + } + return false; + } + @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { } + + @Override public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) { } + } + + /** Interface supplying RecyclerView item position */ + public interface CategoryListener { + public void onItemClick(View view, int position); + } + + // --------------------------------------------------------------------------------------------- + /** Fatal error encountered */ + private void logFatal(String logString) { + debug = true; + log (logString); + } + + /** Override this method via sub-classing to use your preferred logger. */ + public void log(String logString) { + lastLogged = logString; + if (!debug) return; + Log.d("ShowHide", logString); + } +} From 7832babd99c4b647b05042fcf2043dba5304fd78 Mon Sep 17 00:00:00 2001 From: Matt Date: Thu, 16 Jan 2020 09:39:44 +1300 Subject: [PATCH 2/3] Dynamic category expand/collapse --- .../demo/MyPreferenceFragment.java | 23 +++++++++++- .../preferencex/PreferenceShowHide.java | 36 +++++++++++-------- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java b/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java index d637493..4d7e74d 100644 --- a/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java +++ b/app/src/main/java/com/takisoft/preferencex/demo/MyPreferenceFragment.java @@ -4,16 +4,20 @@ import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; import com.takisoft.preferencex.PreferenceFragmentCompat; import com.takisoft.preferencex.PreferenceShowHide; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.recyclerview.widget.RecyclerView; +import static java.lang.String.format; + /** * A placeholder fragment containing a simple view. * Also illustrates optional deployment of {@link PreferenceShowHide} which allows for @@ -30,10 +34,13 @@ public void onCreatePreferencesFix(@Nullable Bundle savedInstanceState, String r testDynamicPrefs(); + String specPref = null; // View all categories + if (false) specPref = "pref_extras"; // Specific category only // Collapse the UI so the user sees only the PreferenceCategory titles. // Tapping the title toggles visibility of the actual Preferences. // Exception: If PreferenceCategory title 'isEmpty()' children are not hidden. - showHide = new PreferenceShowHide(this, null, true); + // [ NB: Does NOT collapse when a specific category or preference is requested. ] + showHide = new PreferenceShowHide(this, specPref, true); Preference prefEmptyCheck = findPreference("pref_empty_check"); @@ -96,4 +103,18 @@ public boolean onPreferenceClick(Preference preference) { return RV; } + /** Specific Preference requested: Remove all other preferences */ + @Override + public void onStart() { + super.onStart(); + + String title = showHide.isSpecific() ? showHide.getSpecPref() : "All preferences"; + + // It's OK to always make this call, which has no effect unless a specific preference + // was requested. (ie when constructor parameter 2 'specPref' is neither null nor empty) + showHide.removeAllButPreviouslySpecifiedPreference(); + + Log.d("onStart()", format("Processing %d preferences for PreferenceScreen key='%s': %s", + RV.getAdapter().getItemCount(), showHide.getRoot(), title)); + } } diff --git a/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java b/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java index b3327a0..5bb85c9 100644 --- a/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java +++ b/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java @@ -47,7 +47,7 @@ public class PreferenceShowHide { private String specPref; // Named PreferenceCategory or Preference public String getSpecPref() { return specPref; } private boolean specific; // Handy flag for above - public boolean isSpecific(){ return specific; }; + public boolean isSpecific(){ return specific; } private boolean debug; // Request/suppress logging private RecyclerView RV = null; /** User responsibility to supply RecyclerView! See 'onCreateRecyclerView()' */ @@ -144,6 +144,7 @@ private void clicked(View v, int position) { int ix = categories.indexOf(cat); log(format("Clicked category '%s' [%d] collapsed=%b", cat, ix, collapsed.get(ix))); for (String key : preferences.get(ix)) { + if (pfc.findPreference(key)==null) continue; // Normal for non-category subset pfc.findPreference(key).setVisible(collapsed.get(ix)); } collapsed.set(ix, !(collapsed.get(ix))); @@ -173,12 +174,13 @@ public void onBindEditText(@NonNull EditText editText) { /** Remove all preferences except the one specified during construction.
    If that was a PreferenceCategory retain visibility of the entire category.
    - Tip: Call this from your PreferenceFragmentCompat 'onStart()' override. */ + Tip: Call this from your PreferenceFragmentCompat 'onStart()' override. It is never unsafe + to make this call as no action is performed when all preferences were requested. */ @SuppressLint("RestrictedApi") public void removeAllButPreviouslySpecifiedPreference() { - if (!isInitOK()) return; + if (!isInitOK() || !specific || RV == null) return; Preference keepPref = pfc.findPreference(specPref); - if (keepPref == null || RV == null) { return;} + if (keepPref == null) { return; } PreferenceGroup keepParent = getParent(keepPref); boolean keepCategory = (root.equals(keepParent.getKey())); log(format("Removing all preferences except '%s/%s'", keepParent.getKey(), specPref)); @@ -198,21 +200,25 @@ public void removeAllButPreviouslySpecifiedPreference() { log(format("remaining=%d", RV.getAdapter().getItemCount())); } - // Obtain the parent of a Preference [ PreferenceScreen OR PreferenceCategory ] - private PreferenceGroup getParent(Preference pref) { - return getParent(pfc.getPreferenceScreen(), pref); + /** Obtain the parent of specified child + @param child Preference (ie: PreferenceCategory OR specific Preference) + @return Parent PreferenceGroup (ie: PreferenceScreen OR PreferenceCategory */ + private PreferenceGroup getParent(Preference child) { + PreferenceGroup parent = getParent(pfc.getPreferenceScreen(), child); + if (parent!=null) log(format("Found child '%s' within parent '%s'", child.getKey(), parent.getKey())); + return parent; } - private PreferenceGroup getParent(PreferenceGroup root, Preference pref) { - for (int i = 0; i < root.getPreferenceCount(); i++) { - Preference p = root.getPreference(i); - if (p == pref) return root; - if (PreferenceGroup.class.isInstance(p)) { - PreferenceGroup parent = getParent((PreferenceGroup)p, pref); + /** Recursively locate parent of specified child */ + private PreferenceGroup getParent(PreferenceGroup group, Preference child) { + for (int i = 0; i < group.getPreferenceCount(); i++) { + Preference p = group.getPreference(i); + if (p == child) return group; + if (p instanceof PreferenceGroup) { // ie: PreferenceScreen/PreferenceCategory + PreferenceGroup parent = getParent((PreferenceGroup)p, child); if (parent != null) return parent; } } - log("Could not find parent for " + pref.getKey()); - return null; + return null; // Not here OR previously removed } // --------------------------------------------------------------------------------------------- From a3fdb6daa36355eadf822b34d1a8c4929c56efc2 Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 17 Jan 2020 12:53:18 +1300 Subject: [PATCH 3/3] Dynamic category expand/collapse --- .../preferencex/PreferenceShowHide.java | 69 ++++++++++++------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java b/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java index 5bb85c9..35b44d6 100644 --- a/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java +++ b/preferencex/src/main/java/com/takisoft/preferencex/PreferenceShowHide.java @@ -2,6 +2,7 @@ import android.annotation.SuppressLint; import android.content.Context; +import android.os.Bundle; import android.util.DisplayMetrics; import android.util.Log; import android.view.GestureDetector; @@ -19,27 +20,36 @@ import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; +import com.takisoft.preferencex.PreferenceFragmentCompat; + import java.util.ArrayList; import java.util.List; import static java.lang.String.format; -// Author: Matt Arnold (GitHub user MPArnold) /** Expand/collapse PreferenceCategory by tapping it's title ...
      Edit your sub-classed PreferenceFragmentCompat as follows:
    -
  • Instantiate this class in onCreatePreferencesFix()
  • -
  • Supply RecyclerView by overriding onCreateRecyclerView()
  • - Refer to the sample app {@link com.takisoft.preferencex.demo.MyPreferenceFragment}
    -
      Additionally ... +
    • Instantiate this class in onCreatePreferencesFix() after xml expansion and all + dynamic modifications have taken place
    • +
    • Supply RecyclerView by overriding onCreateRecyclerView()

    • + Refer to: PreferenceFragmentCompat.onCreatePreferencesFix()
      + +
        Additionally ...
      • Your PreferenceScreen must have a key (eg: "root")
      • Every PreferenceCategory AND Preference will ideally have a unique key
      • Every PreferenceCategory probably should have a title. (Otherwise there is nothing for the user to tap and thereby toggle child Preference visibility)
      • If a PreferenceCategory has an empty title it's children will not be hidden.
      • -
      • If a child Preference has no key, one will be assigned.
      • +
      • If a child Preference has no key, one will be generated.
      • Keys are generally required for internal use by this program but vital should your application wish to display only a specific PreferenceCategory or Preference.
      • -
      */ +
    • Nested PreferenceScreen is tolerated but otherwise unsupported.
    + +
      Scrolling +
    • Default action is to smooth scroll newly-expanded category to top of View.
    • +
    • User may suppress scrolling by issuing setScroll(false).
    • +
    • User may override scrolling. See {@link #setCustomScrollInterface(CustomScroll)}
    + Author: Matt Arnold (GitHub user MPArnold)*/ public class PreferenceShowHide { PreferenceFragmentCompat pfc; // References to caller private String root; // PreferenceScreen name. @@ -68,13 +78,14 @@ public void setRecyclerView(RecyclerView recyclerView) { public boolean isInitOK() { return initOK; } private boolean scroll=true; public void setScroll(boolean scroll) { this.scroll = scroll; } + private CustomScroll customScrollInterface = null; + public void setCustomScrollInterface(CustomScroll iFace) { customScrollInterface = iFace; } /** Constructor. (Caller may issue isInitOK() to test for success.) - @param pfc Your PreferenceFragmentCompat - @param specPref Key of specific PreferenceCategory OR specific Preference OR null/empty - @param debug true: log messages - @see #removeAllButPreviouslySpecifiedPreference() - @see #isInitOK() */ + @param pfc Your PreferenceFragmentCompat + @param specPref Key of specific PreferenceCategory OR specific Preference OR null/empty + @param debug true: log messages + @see #isInitOK() */ public PreferenceShowHide(PreferenceFragmentCompat pfc, String specPref, boolean debug) { this.pfc = pfc; this.specPref = specPref; @@ -84,7 +95,7 @@ public PreferenceShowHide(PreferenceFragmentCompat pfc, String specPref, boolean } /** Analyze XML / Collapse all categories. - @return false Exception described in 'lastLogged' */ + @return false Exception described in 'lastLogged' */ private boolean analyzeXML() { PreferenceScreen ps = pfc.getPreferenceScreen(); root = ps.getKey(); @@ -138,7 +149,7 @@ private boolean analyzeXML() { /** Toggle visibility of all children in the category */ @SuppressLint("RestrictedApi") private void clicked(View v, int position) { - Preference pref = ((PreferenceGroupAdapter) RV.getAdapter()).getItem(position); + Preference pref = ((PreferenceGroupAdapter) RV.getAdapter()).getItem(position); if (!(pref instanceof PreferenceCategory)) return; String cat = pref.getKey(); int ix = categories.indexOf(cat); @@ -150,8 +161,13 @@ private void clicked(View v, int position) { collapsed.set(ix, !(collapsed.get(ix))); if (collapsed.get(ix)) return; - // Smoothly scroll tapped category to top of screen at 1/4 speed - if (scroll) scroll(RV, position); + // Scroll tapped category to top of screen + if (!scroll) return; // User has issued 'setScroll(false)' + if (customScrollInterface != null) { + customScrollInterface.scroll(RV, position); // User-defined scrolling + return; + } + smoothScrollQ(RV, position); // Default scrolling } @@ -171,11 +187,10 @@ public void onBindEditText(@NonNull EditText editText) { } //---------------------------------------------------------------------------------------------- - /** Remove all preferences except the one specified during construction.
    - If that was a PreferenceCategory retain visibility of the entire category.
    - Tip: Call this from your PreferenceFragmentCompat 'onStart()' override. It is never unsafe - to make this call as no action is performed when all preferences were requested. */ + If that was a PreferenceCategory retain visibility of the entire category.
    + Tip: Call this from your PreferenceFragmentCompat 'onStart()' override. It is never unsafe + to make this call as no action is performed when all preferences were requested. */ @SuppressLint("RestrictedApi") public void removeAllButPreviouslySpecifiedPreference() { if (!isInitOK() || !specific || RV == null) return; @@ -222,9 +237,10 @@ private PreferenceGroup getParent(PreferenceGroup group, Preference child) { } // --------------------------------------------------------------------------------------------- + /** Smoothly scroll to specified position at 1/4 speed
    - Extremely primitive but OK for short things like Preferences */ - private void scroll(RecyclerView rv, int position) throws IllegalArgumentException { + This default scroller is extremely primitive but OK for short things like Preferences */ + private void smoothScrollQ(RecyclerView rv, int position) throws IllegalArgumentException { RecyclerView.SmoothScroller smoothScroller = new LinearSmoothScroller(pfc.getContext()) { @Override protected int getVerticalSnapPreference() { return LinearSmoothScroller.SNAP_TO_START; @@ -272,7 +288,14 @@ public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) { /** Interface supplying RecyclerView item position */ public interface CategoryListener { - public void onItemClick(View view, int position); + void onItemClick(View view, int position); + } + + // --------------------------------------------------------------------------------------------- + + /** Custom scroll Interface */ + public interface CustomScroll { + void scroll(RecyclerView rv, int targetPosition); } // ---------------------------------------------------------------------------------------------