Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a Progress Bar in a PreferenceFragment in Android?

How can I add a progress bar in a PreferenceFragment? I have some async task running that will display some values in my preference upon completion. So while it is doing the background process, I plan to show only a progress bar in the center. After the task is complete, then I plan to show all my preferences.

Here's what I have so far.

PreferenceFragment

@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.pref_account);
    }

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    new AsyncTask<Void,Void,Void>() {

        String firstName, lastName, email;
        @Override
        protected void doInBackground() {
            // Doing something here to fetch values
        }

        @Override
        protected void onPostExecute() {
            findPreference("first_name").setSummary(firstName);
            findPreference("last_name").setSummary(lastName);
            findPreference("email").setSummary(email);
        }
    }
}

pref_account.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <Preference android:key="first_name"
        android:title="@string/prompt_first_name"
        android:summary="" />

    <Preference android:key="last_name"
        android:title="@string/prompt_last_name"
        android:summary="" />

    <Preference android:key="email"
        android:title="@string/prompt_email"
        android:summary=""
        android:inputType="textEmailAddress" />

    <Preference android:key="sign_out"
        android:title="@string/action_sign_out" />

</PreferenceScreen>

My question is, since this is a PreferenceFragment and I'm not overriding the method onCreateView, where and how should I add the progress bar?

like image 780
ads Avatar asked Jul 05 '16 02:07

ads


3 Answers

Here's what I did:

  1. Create a custom Preference class:

    public class LoadingPreference extends Preference {
        public LoadingPreference(Context context){
            super(context);
            setLayoutResource(R.layout.preference_loading_placeholder);
        }
    }
    
  2. Create a custom Layout (preference_loading_placeholder) while preserving the Preference layout:

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="?android:attr/listPreferredItemHeight"
        android:gravity="center_vertical"
        android:paddingEnd="?android:attr/scrollbarSize"
        android:background="?android:attr/selectableItemBackground" >
    
        <ImageView
            android:id="@+android:id/icon"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_gravity="center"/>
    
        <RelativeLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="15dip"
            android:layout_marginEnd="6dip"
            android:layout_marginTop="6dip"
            android:layout_marginBottom="6dip"
            android:layout_weight="1">
    
            <!-- (start) I added this part. -->
    
            <ProgressBar
                android:id="@+id/progressBar"
                android:layout_centerInParent="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:indeterminateTintMode="src_atop"
                android:indeterminateTint="@color/colorAccent"
                android:layout_gravity="center" />
    
            <TextView
                android:id="@+id/progressTitle"
                android:text="@string/loading"
                android:textSize="24sp"
                android:textColor="@color/colorAccent"
                android:layout_centerVertical="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="16dp"
                android:layout_toLeftOf="@+id/progressBar" />
    
            <!-- (end) I added this part. -->
    
            <TextView android:id="@+android:id/title"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:singleLine="true"
                android:textAppearance="?android:attr/textAppearanceLarge"
                android:ellipsize="marquee"
                android:fadingEdge="horizontal" />
    
            <TextView android:id="@+id/summary"
                android:layout_width="0dp"
                android:layout_height="0dp"
                android:layout_below="@android:id/title"
                android:layout_alignStart="@android:id/title"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:textColor="?android:attr/textColorSecondary"
                android:maxLines="4" />
    
        </RelativeLayout>
    
        <!-- Preference should place its actual preference widget here. -->
        <LinearLayout android:id="@+id/widget_frame"
             android:layout_width="wrap_content"
             android:layout_height="match_parent"
             android:gravity="center_vertical"
             android:orientation="vertical"/>
    
    </LinearLayout>
    
  3. Used a PreferenceCategory to hold my loading preference:

    <?xml version="1.0" encoding="utf-8"?>
    <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    
        <SwitchPreference
            android:key="@string/pref_key_wifi_enabled"
            android:title="@string/pref_title_wifi_enabled"
            android:summary="@string/pref_summary_wifi_enabled" />
    
        <Preference
            android:key="@string/pref_key_wifi_refresh"
            android:title="@string/pref_title_wifi_refresh"
            android:summary="@string/pref_summary_wifi_refresh"
            android:dependency="@string/pref_key_wifi_enabled"/>
    
        <PreferenceCategory
            android:key="@string/pref_key_wifi_section"
            android:title="@string/pref_title_wifi_section"
            android:summary="@string/pref_summary_wifi_section"
            android:dependency="@string/pref_key_wifi_enabled"/>
    
    </PreferenceScreen>
    
  4. Put the loading preference where needed

    ((PreferenceCategory)findPreference(WIFI_OPTIONS_SECTION_KEY)).addPreference(new LoadingPreference(getActivity()));
    
  5. Remove the loading preference after loading is complete:

    ((PreferenceCategory)findPreference(WIFI_OPTIONS_SECTION_KEY)).removeAll();
    
  6. Add other preferences after loading is complete:

    Preference p = new Preference(getActivity());
    p.setTitle("...");
    p.setSumary("...")     
    ((PreferenceCategory)findPreference(WIFI_OPTIONS_SECTION_KEY)).addPreferece(p);
    

Loading Fragment Example

like image 190
Aaron Preston Avatar answered Oct 17 '22 23:10

Aaron Preston


I had a similar use case and I used a custom layout for the preference.

In the preference fragment file I had (non relevant attributes are omitted)

<!-- res/xml/somePref.xml -->
<PreferenceScreen>
    <PreferenceCategory>
        ...
        <Preference android:widgetLayout="@layout/customLayout" />
        ...
    </PreferenceCategory>
</PreferenceScreen>

Then in the custom layout I placed the progress bar by itself

<!-- res/layout/customLayout.xml -->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/progress"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone">

    <ProgressBar
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:indeterminateOnly="true" />

</RelativeLayout>

Before starting the async task I call

findViewById(R.id.progress).setVisibility(View.VISIBLE)

and when the task is done I set the visibility back to gone. This will allow you to set each preference independently without having to wait for each one to complete. Hope this helps.

like image 28
Liviu Avatar answered Oct 18 '22 00:10

Liviu


I ended up using the following approach.

In my fragment_account.xml layout file.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone" />

</RelativeLayout>

Then on my class:

public class AccountFragment extends PreferenceFragment {

        private ListView mListView;
        private ProgressBar mProgressBar;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_account, container, false);

            mListView = (ListView) view.findViewById(android.R.id.list);
            mProgressBar = (ProgressBar) view.findViewById(R.id.progress_bar);

            showProgress();

            return view;
        }

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_account);
            hideProgress();
        }

        private void showProgress() {
            mListView.setVisibility(View.GONE);
            mProgressBar.setVisibility(View.VISIBLE);
        }

        private void hideProgress() {
            mListView.setVisibility(View.VISIBLE);
            mProgressBar.setVisibility(View.GONE);
        }
    }

}
like image 43
ads Avatar answered Oct 17 '22 22:10

ads