Create empty view for RecyclerViewFragment
This commit is contained in:
parent
34930fa2b3
commit
edf33240e6
@ -1,7 +1,10 @@
|
||||
package com.philliphsu.clock2;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
@ -9,8 +12,10 @@ import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.philliphsu.clock2.alarms.ScrollHandler;
|
||||
import com.philliphsu.clock2.aospdatetimepicker.Utils;
|
||||
import com.philliphsu.clock2.model.BaseItemCursor;
|
||||
import com.philliphsu.clock2.model.ObjectWithId;
|
||||
|
||||
@ -34,7 +39,12 @@ public abstract class RecyclerViewFragment<
|
||||
|
||||
// TODO: Rename id to recyclerView?
|
||||
// TODO: Rename variable to mRecyclerView?
|
||||
@Bind(R.id.list) RecyclerView mList;
|
||||
@Bind(R.id.list)
|
||||
RecyclerView mList;
|
||||
|
||||
@Nullable // Subclasses are not required to use the default content layout, so this may not be present.
|
||||
@Bind(R.id.empty_view)
|
||||
TextView mEmptyView;
|
||||
|
||||
public abstract void onFabClick();
|
||||
|
||||
@ -51,6 +61,33 @@ public abstract class RecyclerViewFragment<
|
||||
*/
|
||||
protected abstract A onCreateAdapter();
|
||||
|
||||
/**
|
||||
* @return a resource to a String that will be displayed when the list is empty
|
||||
*/
|
||||
@StringRes
|
||||
protected int emptyMessage() {
|
||||
// The reason this isn't abstract is so we don't require subclasses that
|
||||
// don't have an empty view to implement this.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a resource to a Drawable that will be displayed when the list is empty
|
||||
*/
|
||||
@DrawableRes
|
||||
protected int emptyMessageIcon() {
|
||||
// TODO: If this is the same for all RecyclerViewFragments, then why not just specify
|
||||
// the compound drawable in XML?
|
||||
return R.drawable.ic_empty_list_96dp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether the list should show an empty view when its adapter has an item count of zero
|
||||
*/
|
||||
protected boolean hasEmptyView() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the adapter instance created from {@link #onCreateAdapter()}
|
||||
*/
|
||||
@ -73,6 +110,13 @@ public abstract class RecyclerViewFragment<
|
||||
View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
mList.setLayoutManager(getLayoutManager());
|
||||
mList.setAdapter(mAdapter = onCreateAdapter());
|
||||
if (hasEmptyView() && mEmptyView != null) {
|
||||
// Configure the empty view, even if there currently are items.
|
||||
mEmptyView.setText(emptyMessage());
|
||||
int iconColor = Utils.getTextColorFromThemeAttr(getActivity(), R.attr.themedIconTint);
|
||||
Drawable emptyMessageIcon = Utils.getTintedDrawable(getActivity(), emptyMessageIcon(), iconColor);
|
||||
mEmptyView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, emptyMessageIcon, null, null);
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@ -87,6 +131,12 @@ public abstract class RecyclerViewFragment<
|
||||
@Override
|
||||
public void onLoadFinished(Loader<C> loader, C data) {
|
||||
mAdapter.swapCursor(data);
|
||||
if (hasEmptyView() && mEmptyView != null) {
|
||||
// TODO: Last I checked after a fresh install, this worked fine.
|
||||
// However, previous attempts (without fresh installs) didn't hide the empty view
|
||||
// upon an item being added. Verify this is no longer the case.
|
||||
mEmptyView.setVisibility(mAdapter.getItemCount() == 0 ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
// This may have been a requery due to content change. If the change
|
||||
// was an insertion, scroll to the last modified alarm.
|
||||
performScrollToStableId();
|
||||
|
||||
@ -146,6 +146,11 @@ public class AlarmsFragment extends RecyclerViewFragment<
|
||||
return new AlarmsCursorAdapter(this, mAlarmController);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int emptyMessage() {
|
||||
return R.string.empty_alarms_container;
|
||||
}
|
||||
|
||||
// TODO: We're not using EditAlarmActivity anymore, so move this logic somewhere else.
|
||||
// We also don't need to delay the change to get animations working.
|
||||
@Override
|
||||
|
||||
@ -160,6 +160,11 @@ public class StopwatchFragment extends RecyclerViewFragment<
|
||||
+ ", mPauseTime = " + mPauseTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasEmptyView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<LapCursor> onCreateLoader(int id, Bundle args) {
|
||||
return new LapsCursorLoader(getActivity());
|
||||
|
||||
@ -102,6 +102,11 @@ public class TimersFragment extends RecyclerViewFragment<
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int emptyMessage() {
|
||||
return R.string.empty_timers_container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<TimerCursor> onCreateLoader(int id, Bundle args) {
|
||||
return new TimersListCursorLoader(getActivity());
|
||||
|
||||
4
app/src/main/res/drawable/ic_empty_list_96dp.xml
Normal file
4
app/src/main/res/drawable/ic_empty_list_96dp.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<vector android:height="96dp" android:viewportHeight="24.0"
|
||||
android:viewportWidth="24.0" android:width="96dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M14.59,8L12,10.59 9.41,8 8,9.41 10.59,12 8,14.59 9.41,16 12,13.41 14.59,16 16,14.59 13.41,12 16,9.41 14.59,8zM12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||
</vector>
|
||||
@ -1,21 +1,36 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- clipToPadding specifies whether padding should cut into the
|
||||
- view bounds, and hence into the children. To us, setting
|
||||
- this to false has the effect of padding the bottom with
|
||||
- extra space so the FAB isn't covering the last item
|
||||
- when we scroll to it.
|
||||
-
|
||||
- An outsideOverlay scrollbarStyle means the scrollbar is drawn
|
||||
- outside of the clipping boundary due to padding, and is laid over
|
||||
- the RecyclerView, rather than being inside of its container (which
|
||||
- mandates it being inset and adding to the view's padding).
|
||||
-->
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="@dimen/fab_total_height"/>
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- clipToPadding specifies whether padding should cut into the
|
||||
- view bounds, and hence into the children. To us, setting
|
||||
- this to false has the effect of padding the bottom with
|
||||
- extra space so the FAB isn't covering the last item
|
||||
- when we scroll to it.
|
||||
-
|
||||
- An outsideOverlay scrollbarStyle means the scrollbar is drawn
|
||||
- outside of the clipping boundary due to padding, and is laid over
|
||||
- the RecyclerView, rather than being inside of its container (which
|
||||
- mandates it being inset and adding to the view's padding).
|
||||
-->
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="@dimen/fab_total_height"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/empty_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:gravity="center"
|
||||
android:textSize="@dimen/text_size_headline"
|
||||
android:drawablePadding="@dimen/text_compound_drawable_padding"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@ -200,4 +200,7 @@
|
||||
|
||||
<string name="pause">Pause</string>
|
||||
<string name="resume">Resume</string>
|
||||
|
||||
<string name="empty_alarms_container">No alarms added</string>
|
||||
<string name="empty_timers_container">No timers added</string>
|
||||
</resources>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user