Updated our RecyclerView to handle onClick and empty view.

This commit is contained in:
Dan Galpin
2015-05-25 03:04:38 -07:00
parent c4d1dffc5e
commit 8ccc514346
3 changed files with 54 additions and 36 deletions

View File

@@ -17,15 +17,18 @@ package com.example.android.sunshine.app;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.os.Build;
import android.support.v4.view.ViewCompat; import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Checkable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.example.android.sunshine.app.data.WeatherContract;
/** /**
* {@link ForecastAdapter} exposes a list of weather forecasts * {@link ForecastAdapter} exposes a list of weather forecasts
@@ -41,11 +44,13 @@ public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.Foreca
private Cursor mCursor; private Cursor mCursor;
final private Context mContext; final private Context mContext;
final private ForecastAdapterOnClickHandler mClickHandler;
final private View mEmptyView;
/** /**
* Cache of the children views for a forecast list item. * Cache of the children views for a forecast list item.
*/ */
public class ForecastAdapterViewHolder extends RecyclerView.ViewHolder { public class ForecastAdapterViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final ImageView mIconView; public final ImageView mIconView;
public final TextView mDateView; public final TextView mDateView;
public final TextView mDescriptionView; public final TextView mDescriptionView;
@@ -59,11 +64,26 @@ public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.Foreca
mDescriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview); mDescriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview);
mHighTempView = (TextView) view.findViewById(R.id.list_item_high_textview); mHighTempView = (TextView) view.findViewById(R.id.list_item_high_textview);
mLowTempView = (TextView) view.findViewById(R.id.list_item_low_textview); mLowTempView = (TextView) view.findViewById(R.id.list_item_low_textview);
view.setOnClickListener(this);
}
@Override
public void onClick(View v) {
int adapterPosition = getAdapterPosition();
mCursor.moveToPosition(adapterPosition);
int dateColumnIndex = mCursor.getColumnIndex(WeatherContract.WeatherEntry.COLUMN_DATE);
mClickHandler.onClick(mCursor.getLong(dateColumnIndex), this);
} }
} }
public ForecastAdapter(Context context) { public static interface ForecastAdapterOnClickHandler {
void onClick(Long date, ForecastAdapterViewHolder vh);
}
public ForecastAdapter(Context context, ForecastAdapterOnClickHandler dh, View emptyView) {
mContext = context; mContext = context;
mClickHandler = dh;
mEmptyView = emptyView;
} }
/* /*
@@ -92,7 +112,7 @@ public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.Foreca
view.setFocusable(true); view.setFocusable(true);
return new ForecastAdapterViewHolder(view); return new ForecastAdapterViewHolder(view);
} else { } else {
throw new RuntimeException("Not bound to RecyclerViewSelection"); throw new RuntimeException("Not bound to RecyclerView");
} }
} }
@@ -170,6 +190,7 @@ public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.Foreca
public void swapCursor(Cursor newCursor) { public void swapCursor(Cursor newCursor) {
mCursor = newCursor; mCursor = newCursor;
notifyDataSetChanged(); notifyDataSetChanged();
mEmptyView.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
} }
public Cursor getCursor() { public Cursor getCursor() {

View File

@@ -40,7 +40,7 @@ import com.example.android.sunshine.app.data.WeatherContract;
import com.example.android.sunshine.app.sync.SunshineSyncAdapter; import com.example.android.sunshine.app.sync.SunshineSyncAdapter;
/** /**
* Encapsulates fetching the forecast and displaying it as a {@link RecyclerView} layout. * Encapsulates fetching the forecast and displaying it as a {@link android.support.v7.widget.RecyclerView} layout.
*/ */
public class ForecastFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, SharedPreferences.OnSharedPreferenceChangeListener { public class ForecastFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor>, SharedPreferences.OnSharedPreferenceChangeListener {
public static final String LOG_TAG = ForecastFragment.class.getSimpleName(); public static final String LOG_TAG = ForecastFragment.class.getSimpleName();
@@ -148,9 +148,6 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
// The ForecastAdapter will take data from a source and
// use it to populate the RecyclerView it's attached to.
mForecastAdapter = new ForecastAdapter(getActivity());
View rootView = inflater.inflate(R.layout.fragment_main, container, false); View rootView = inflater.inflate(R.layout.fragment_main, container, false);
@@ -159,26 +156,28 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
// Set the layout manager // Set the layout manager
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// View emptyView = rootView.findViewById(R.id.recyclerview_forecast_empty); View emptyView = rootView.findViewById(R.id.recyclerview_forecast_empty);
// use this setting to improve performance if you know that changes
// in content do not change the layout size of the RecyclerView
mRecyclerView.setHasFixedSize(true);
// The ForecastAdapter will take data from a source and
// use it to populate the RecyclerView it's attached to.
mForecastAdapter = new ForecastAdapter(getActivity(), new ForecastAdapter.ForecastAdapterOnClickHandler() {
@Override
public void onClick(Long date, ForecastAdapter.ForecastAdapterViewHolder vh) {
String locationSetting = Utility.getPreferredLocation(getActivity());
((Callback) getActivity())
.onItemSelected(WeatherContract.WeatherEntry.buildWeatherLocationWithDate(
locationSetting, date)
);
mPosition = vh.getAdapterPosition();
}
}, emptyView);
// specify an adapter (see also next example)
mRecyclerView.setAdapter(mForecastAdapter); mRecyclerView.setAdapter(mForecastAdapter);
// We'll call our MainActivity
// mRecyclerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
//
// @Override
// public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
// // CursorAdapter returns a cursor at the correct position for getItem(), or null
// // if it cannot seek to that position.
// Cursor cursor = (Cursor) adapterView.getItemAtPosition(position);
// if (cursor != null) {
// String locationSetting = Utility.getPreferredLocation(getActivity());
// ((Callback) getActivity())
// .onItemSelected(WeatherContract.WeatherEntry.buildWeatherLocationWithDate(
// locationSetting, cursor.getLong(COL_WEATHER_DATE)
// ));
// }
// mPosition = position;
// }
// });
// If there's instance state, mine it for useful information. // If there's instance state, mine it for useful information.
// The end-goal here is that the user never knows that turning their device sideways // The end-goal here is that the user never knows that turning their device sideways
@@ -186,7 +185,7 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
// or magically appeared to take advantage of room, but data or place in the app was never // or magically appeared to take advantage of room, but data or place in the app was never
// actually *lost*. // actually *lost*.
if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) { if (savedInstanceState != null && savedInstanceState.containsKey(SELECTED_KEY)) {
// The RecyclerView probably hasn't even been populated yet. Actually perform the // The Recycler View probably hasn't even been populated yet. Actually perform the
// swapout in onLoadFinished. // swapout in onLoadFinished.
mPosition = savedInstanceState.getInt(SELECTED_KEY); mPosition = savedInstanceState.getInt(SELECTED_KEY);
} }
@@ -203,7 +202,7 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
} }
// since we read the location when we create the loader, all we need to do is restart things // since we read the location when we create the loader, all we need to do is restart things
void onLocationChanged( ) { void onLocationChanged() {
getLoaderManager().restartLoader(FORECAST_LOADER, null, this); getLoaderManager().restartLoader(FORECAST_LOADER, null, this);
} }
@@ -211,9 +210,9 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
// Using the URI scheme for showing a location found on a map. This super-handy // Using the URI scheme for showing a location found on a map. This super-handy
// intent can is detailed in the "Common Intents" page of Android's developer site: // intent can is detailed in the "Common Intents" page of Android's developer site:
// http://developer.android.com/guide/components/intents-common.html#Maps // http://developer.android.com/guide/components/intents-common.html#Maps
if ( null != mForecastAdapter ) { if (null != mForecastAdapter) {
Cursor c = mForecastAdapter.getCursor(); Cursor c = mForecastAdapter.getCursor();
if ( null != c ) { if (null != c) {
c.moveToPosition(0); c.moveToPosition(0);
String posLat = c.getString(COL_COORD_LAT); String posLat = c.getString(COL_COORD_LAT);
String posLong = c.getString(COL_COORD_LONG); String posLong = c.getString(COL_COORD_LONG);
@@ -235,7 +234,7 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
// When tablets rotate, the currently selected list item needs to be saved. // When tablets rotate, the currently selected list item needs to be saved.
// When no item is selected, mPosition will be set to RecyclerView.INVALID_POSITION, // When no item is selected, mPosition will be set to RecyclerView.NO_POSITION,
// so check for that before storing. // so check for that before storing.
if (mPosition != RecyclerView.NO_POSITION) { if (mPosition != RecyclerView.NO_POSITION) {
outState.putInt(SELECTED_KEY, mPosition); outState.putInt(SELECTED_KEY, mPosition);
@@ -311,7 +310,7 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
message = R.string.empty_forecast_list_invalid_location; message = R.string.empty_forecast_list_invalid_location;
break; break;
default: default:
if (!Utility.isNetworkAvailable(getActivity()) ) { if (!Utility.isNetworkAvailable(getActivity())) {
message = R.string.empty_forecast_list_no_network; message = R.string.empty_forecast_list_no_network;
} }
} }
@@ -322,9 +321,8 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if ( key.equals(getString(R.string.pref_location_status_key)) ) { if (key.equals(getString(R.string.pref_location_status_key))) {
updateEmptyView(); updateEmptyView();
} }
} }
} }

View File

@@ -23,8 +23,7 @@
style="@style/ForecastListStyle" style="@style/ForecastListStyle"
android:id="@+id/recyclerview_forecast" android:id="@+id/recyclerview_forecast"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"/>
android:divider="@null" />
<!-- empty list --> <!-- empty list -->
<TextView <TextView
android:id="@+id/recyclerview_forecast_empty" android:id="@+id/recyclerview_forecast_empty"