Updated Sunshine to start using RecyclerView instead of ListView.
This commit is contained in:
@@ -26,5 +26,6 @@ dependencies {
|
|||||||
compile 'com.android.support:support-annotations:22.1.0'
|
compile 'com.android.support:support-annotations:22.1.0'
|
||||||
compile 'com.android.support:gridlayout-v7:22.1.0'
|
compile 'com.android.support:gridlayout-v7:22.1.0'
|
||||||
compile 'com.android.support:cardview-v7:22.1.1'
|
compile 'com.android.support:cardview-v7:22.1.1'
|
||||||
|
compile 'com.android.support:recyclerview-v7:22.1.1'
|
||||||
compile 'com.google.android.gms:play-services-gcm:7.0.0'
|
compile 'com.google.android.gms:play-services-gcm:7.0.0'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,8 @@ package com.example.android.sunshine.app;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.support.v4.widget.CursorAdapter;
|
import android.support.v4.view.ViewCompat;
|
||||||
|
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;
|
||||||
@@ -28,28 +29,31 @@ import com.bumptech.glide.Glide;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ForecastAdapter} exposes a list of weather forecasts
|
* {@link ForecastAdapter} exposes a list of weather forecasts
|
||||||
* from a {@link Cursor} to a {@link android.widget.ListView}.
|
* from a {@link android.database.Cursor} to a {@link android.support.v7.widget.RecyclerView}.
|
||||||
*/
|
*/
|
||||||
public class ForecastAdapter extends CursorAdapter {
|
public class ForecastAdapter extends RecyclerView.Adapter<ForecastAdapter.ForecastAdapterViewHolder> {
|
||||||
|
|
||||||
private static final int VIEW_TYPE_COUNT = 2;
|
|
||||||
private static final int VIEW_TYPE_TODAY = 0;
|
private static final int VIEW_TYPE_TODAY = 0;
|
||||||
private static final int VIEW_TYPE_FUTURE_DAY = 1;
|
private static final int VIEW_TYPE_FUTURE_DAY = 1;
|
||||||
|
|
||||||
// Flag to determine if we want to use a separate view for "today".
|
// Flag to determine if we want to use a separate view for "today".
|
||||||
private boolean mUseTodayLayout = true;
|
private boolean mUseTodayLayout = true;
|
||||||
|
|
||||||
|
private Cursor mCursor;
|
||||||
|
final private Context mContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache of the children views for a forecast list item.
|
* Cache of the children views for a forecast list item.
|
||||||
*/
|
*/
|
||||||
public static class ViewHolder {
|
public class ForecastAdapterViewHolder extends RecyclerView.ViewHolder {
|
||||||
public final ImageView mIconView;
|
public final ImageView mIconView;
|
||||||
public final TextView mDateView;
|
public final TextView mDateView;
|
||||||
public final TextView mDescriptionView;
|
public final TextView mDescriptionView;
|
||||||
public final TextView mHighTempView;
|
public final TextView mHighTempView;
|
||||||
public final TextView mLowTempView;
|
public final TextView mLowTempView;
|
||||||
|
|
||||||
public ViewHolder(View view) {
|
public ForecastAdapterViewHolder(View view) {
|
||||||
|
super(view);
|
||||||
mIconView = (ImageView) view.findViewById(R.id.list_item_icon);
|
mIconView = (ImageView) view.findViewById(R.id.list_item_icon);
|
||||||
mDateView = (TextView) view.findViewById(R.id.list_item_date_textview);
|
mDateView = (TextView) view.findViewById(R.id.list_item_date_textview);
|
||||||
mDescriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview);
|
mDescriptionView = (TextView) view.findViewById(R.id.list_item_forecast_textview);
|
||||||
@@ -58,42 +62,47 @@ public class ForecastAdapter extends CursorAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ForecastAdapter(Context context, Cursor c, int flags) {
|
public ForecastAdapter(Context context) {
|
||||||
super(context, c, flags);
|
mContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
This takes advantage of the fact that the viewGroup passed to onCreateViewHolder is the
|
||||||
|
RecyclerView that will be used to contain the view, so that it can get the current
|
||||||
|
ItemSelectionManager from the view.
|
||||||
|
|
||||||
|
One could implement this pattern without modifying RecyclerView by taking advantage
|
||||||
|
of the view tag to store the ItemChoiceManager.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
public ForecastAdapterViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
|
||||||
// Choose the layout type
|
if ( viewGroup instanceof RecyclerView ) {
|
||||||
int viewType = getItemViewType(cursor.getPosition());
|
int layoutId = -1;
|
||||||
int layoutId = -1;
|
switch (viewType) {
|
||||||
switch (viewType) {
|
case VIEW_TYPE_TODAY: {
|
||||||
case VIEW_TYPE_TODAY: {
|
layoutId = R.layout.list_item_forecast_today;
|
||||||
layoutId = R.layout.list_item_forecast_today;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case VIEW_TYPE_FUTURE_DAY: {
|
||||||
case VIEW_TYPE_FUTURE_DAY: {
|
layoutId = R.layout.list_item_forecast;
|
||||||
layoutId = R.layout.list_item_forecast;
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutId, viewGroup, false);
|
||||||
|
view.setFocusable(true);
|
||||||
|
return new ForecastAdapterViewHolder(view);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Not bound to RecyclerViewSelection");
|
||||||
}
|
}
|
||||||
|
|
||||||
View view = LayoutInflater.from(context).inflate(layoutId, parent, false);
|
|
||||||
|
|
||||||
ViewHolder viewHolder = new ViewHolder(view);
|
|
||||||
view.setTag(viewHolder);
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bindView(View view, Context context, Cursor cursor) {
|
public void onBindViewHolder(ForecastAdapterViewHolder forecastAdapterViewHolder, int position) {
|
||||||
|
mCursor.moveToPosition(position);
|
||||||
ViewHolder viewHolder = (ViewHolder) view.getTag();
|
int weatherId = mCursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
|
||||||
int weatherId = cursor.getInt(ForecastFragment.COL_WEATHER_CONDITION_ID);
|
|
||||||
int defaultImage;
|
int defaultImage;
|
||||||
|
|
||||||
switch (getItemViewType(cursor.getPosition())) {
|
switch (getItemViewType(position)) {
|
||||||
case VIEW_TYPE_TODAY:
|
case VIEW_TYPE_TODAY:
|
||||||
defaultImage = Utility.getArtResourceForWeatherCondition(weatherId);
|
defaultImage = Utility.getArtResourceForWeatherCondition(weatherId);
|
||||||
break;
|
break;
|
||||||
@@ -101,27 +110,28 @@ public class ForecastAdapter extends CursorAdapter {
|
|||||||
defaultImage = Utility.getIconResourceForWeatherCondition(weatherId);
|
defaultImage = Utility.getIconResourceForWeatherCondition(weatherId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Utility.usingLocalGraphics(mContext)) {
|
if ( Utility.usingLocalGraphics(mContext) ) {
|
||||||
viewHolder.mIconView.
|
forecastAdapterViewHolder.mIconView.setImageResource(defaultImage);
|
||||||
setImageResource(defaultImage);
|
|
||||||
} else {
|
} else {
|
||||||
Glide.with(mContext)
|
Glide.with(mContext)
|
||||||
.load(Utility.getArtUrlForWeatherCondition(mContext, weatherId))
|
.load(Utility.getArtUrlForWeatherCondition(mContext, weatherId))
|
||||||
.error(defaultImage)
|
.error(defaultImage)
|
||||||
.crossFade()
|
.crossFade()
|
||||||
.into(viewHolder.mIconView);
|
.into(forecastAdapterViewHolder.mIconView);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read date from cursor
|
// Read date from cursor
|
||||||
long dateInMillis = cursor.getLong(ForecastFragment.COL_WEATHER_DATE);
|
long dateInMillis = mCursor.getLong(ForecastFragment.COL_WEATHER_DATE);
|
||||||
|
|
||||||
// Find TextView and set formatted date on it
|
// Find TextView and set formatted date on it
|
||||||
viewHolder.mDateView.setText(Utility.getFriendlyDayString(context, dateInMillis));
|
forecastAdapterViewHolder.mDateView.setText(Utility.getFriendlyDayString(mContext, dateInMillis));
|
||||||
|
|
||||||
// Read weather forecast from cursor
|
// Read weather forecast from cursor
|
||||||
String description = Utility.getStringForWeatherCondition(mContext, weatherId);
|
String description = Utility.getStringForWeatherCondition(mContext, weatherId);
|
||||||
|
|
||||||
// Find TextView and set weather forecast on it
|
// Find TextView and set weather forecast on it
|
||||||
viewHolder.mDescriptionView.setText(description);
|
forecastAdapterViewHolder.mDescriptionView.setText(description);
|
||||||
viewHolder.mDescriptionView.setContentDescription(mContext.getString(R.string.a11y_forecast, description));
|
forecastAdapterViewHolder.mDescriptionView.setContentDescription(mContext.getString(R.string.a11y_forecast, description));
|
||||||
|
|
||||||
// For accessibility, we don't want a content description for the icon field
|
// For accessibility, we don't want a content description for the icon field
|
||||||
// because the information is repeated in the description view and the icon
|
// because the information is repeated in the description view and the icon
|
||||||
@@ -130,27 +140,39 @@ public class ForecastAdapter extends CursorAdapter {
|
|||||||
// Read high temperature from cursor
|
// Read high temperature from cursor
|
||||||
double high = mCursor.getDouble(ForecastFragment.COL_WEATHER_MAX_TEMP);
|
double high = mCursor.getDouble(ForecastFragment.COL_WEATHER_MAX_TEMP);
|
||||||
String highString = Utility.formatTemperature(mContext, high);
|
String highString = Utility.formatTemperature(mContext, high);
|
||||||
viewHolder.mHighTempView.setText(highString);
|
forecastAdapterViewHolder.mHighTempView.setText(highString);
|
||||||
viewHolder.mHighTempView.setContentDescription(mContext.getString(R.string.a11y_high_temp, highString));
|
forecastAdapterViewHolder.mHighTempView.setContentDescription(mContext.getString(R.string.a11y_high_temp, highString));
|
||||||
|
|
||||||
// Read low temperature from cursor
|
// Read low temperature from cursor
|
||||||
double low = mCursor.getDouble(ForecastFragment.COL_WEATHER_MIN_TEMP);
|
double low = mCursor.getDouble(ForecastFragment.COL_WEATHER_MIN_TEMP);
|
||||||
String lowString = Utility.formatTemperature(mContext, low);
|
String lowString = Utility.formatTemperature(mContext, low);
|
||||||
viewHolder.mLowTempView.setText(lowString);
|
forecastAdapterViewHolder.mLowTempView.setText(lowString);
|
||||||
viewHolder.mLowTempView.setContentDescription(mContext.getString(R.string.a11y_low_temp, lowString));
|
forecastAdapterViewHolder.mLowTempView.setContentDescription(mContext.getString(R.string.a11y_low_temp, lowString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setUseTodayLayout(boolean useTodayLayout) {
|
public void setUseTodayLayout(boolean useTodayLayout) {
|
||||||
mUseTodayLayout = useTodayLayout;
|
mUseTodayLayout = useTodayLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getItemViewType(int position) {
|
public int getItemViewType(int position) {
|
||||||
return (position == 0 && mUseTodayLayout) ? VIEW_TYPE_TODAY : VIEW_TYPE_FUTURE_DAY;
|
return (position == 0 && mUseTodayLayout) ? VIEW_TYPE_TODAY : VIEW_TYPE_FUTURE_DAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getViewTypeCount() {
|
public int getItemCount() {
|
||||||
return VIEW_TYPE_COUNT;
|
if ( null == mCursor ) return 0;
|
||||||
|
return mCursor.getCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swapCursor(Cursor newCursor) {
|
||||||
|
mCursor = newCursor;
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cursor getCursor() {
|
||||||
|
return mCursor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,8 @@ import android.support.v4.app.Fragment;
|
|||||||
import android.support.v4.app.LoaderManager;
|
import android.support.v4.app.LoaderManager;
|
||||||
import android.support.v4.content.CursorLoader;
|
import android.support.v4.content.CursorLoader;
|
||||||
import android.support.v4.content.Loader;
|
import android.support.v4.content.Loader;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
@@ -32,22 +34,20 @@ import android.view.MenuInflater;
|
|||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.AdapterView;
|
|
||||||
import android.widget.ListView;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.example.android.sunshine.app.data.WeatherContract;
|
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 ListView} layout.
|
* Encapsulates fetching the forecast and displaying it as a {@link 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();
|
||||||
private ForecastAdapter mForecastAdapter;
|
private ForecastAdapter mForecastAdapter;
|
||||||
|
|
||||||
private ListView mListView;
|
private RecyclerView mRecyclerView;
|
||||||
private int mPosition = ListView.INVALID_POSITION;
|
private int mPosition = RecyclerView.NO_POSITION;
|
||||||
private boolean mUseTodayLayout;
|
private boolean mUseTodayLayout;
|
||||||
|
|
||||||
private static final String SELECTED_KEY = "selected_position";
|
private static final String SELECTED_KEY = "selected_position";
|
||||||
@@ -149,34 +149,36 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
|
|
||||||
// The ForecastAdapter will take data from a source and
|
// The ForecastAdapter will take data from a source and
|
||||||
// use it to populate the ListView it's attached to.
|
// use it to populate the RecyclerView it's attached to.
|
||||||
mForecastAdapter = new ForecastAdapter(getActivity(), null, 0);
|
mForecastAdapter = new ForecastAdapter(getActivity());
|
||||||
|
|
||||||
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
|
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
|
||||||
|
|
||||||
// Get a reference to the ListView, and attach this adapter to it.
|
// Get a reference to the RecyclerView, and attach this adapter to it.
|
||||||
mListView = (ListView) rootView.findViewById(R.id.listview_forecast);
|
mRecyclerView = (RecyclerView) rootView.findViewById(R.id.recyclerview_forecast);
|
||||||
View emptyView = rootView.findViewById(R.id.listview_forecast_empty);
|
|
||||||
mListView.setEmptyView(emptyView);
|
|
||||||
mListView.setAdapter(mForecastAdapter);
|
|
||||||
// We'll call our MainActivity
|
|
||||||
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
|
||||||
|
|
||||||
@Override
|
// Set the layout manager
|
||||||
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
|
mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||||
// CursorAdapter returns a cursor at the correct position for getItem(), or null
|
// View emptyView = rootView.findViewById(R.id.recyclerview_forecast_empty);
|
||||||
// if it cannot seek to that position.
|
mRecyclerView.setAdapter(mForecastAdapter);
|
||||||
Cursor cursor = (Cursor) adapterView.getItemAtPosition(position);
|
// We'll call our MainActivity
|
||||||
if (cursor != null) {
|
// mRecyclerView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||||
String locationSetting = Utility.getPreferredLocation(getActivity());
|
//
|
||||||
((Callback) getActivity())
|
// @Override
|
||||||
.onItemSelected(WeatherContract.WeatherEntry.buildWeatherLocationWithDate(
|
// public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
|
||||||
locationSetting, cursor.getLong(COL_WEATHER_DATE)
|
// // 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);
|
||||||
mPosition = 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
|
||||||
@@ -184,7 +186,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 listview probably hasn't even been populated yet. Actually perform the
|
// The RecyclerView 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);
|
||||||
}
|
}
|
||||||
@@ -233,9 +235,9 @@ 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 Listview.INVALID_POSITION,
|
// When no item is selected, mPosition will be set to RecyclerView.INVALID_POSITION,
|
||||||
// so check for that before storing.
|
// so check for that before storing.
|
||||||
if (mPosition != ListView.INVALID_POSITION) {
|
if (mPosition != RecyclerView.NO_POSITION) {
|
||||||
outState.putInt(SELECTED_KEY, mPosition);
|
outState.putInt(SELECTED_KEY, mPosition);
|
||||||
}
|
}
|
||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
@@ -267,10 +269,10 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
|
|||||||
@Override
|
@Override
|
||||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
|
||||||
mForecastAdapter.swapCursor(data);
|
mForecastAdapter.swapCursor(data);
|
||||||
if (mPosition != ListView.INVALID_POSITION) {
|
if (mPosition != RecyclerView.NO_POSITION) {
|
||||||
// If we don't need to restart the loader, and there's a desired position to restore
|
// If we don't need to restart the loader, and there's a desired position to restore
|
||||||
// to, do so now.
|
// to, do so now.
|
||||||
mListView.smoothScrollToPosition(mPosition);
|
mRecyclerView.smoothScrollToPosition(mPosition);
|
||||||
}
|
}
|
||||||
updateEmptyView();
|
updateEmptyView();
|
||||||
}
|
}
|
||||||
@@ -292,8 +294,8 @@ public class ForecastFragment extends Fragment implements LoaderManager.LoaderCa
|
|||||||
use to determine why they aren't seeing weather.
|
use to determine why they aren't seeing weather.
|
||||||
*/
|
*/
|
||||||
private void updateEmptyView() {
|
private void updateEmptyView() {
|
||||||
if ( mForecastAdapter.getCount() == 0 ) {
|
if ( mForecastAdapter.getItemCount() == 0 ) {
|
||||||
TextView tv = (TextView) getView().findViewById(R.id.listview_forecast_empty);
|
TextView tv = (TextView) getView().findViewById(R.id.recyclerview_forecast_empty);
|
||||||
if ( null != tv ) {
|
if ( null != tv ) {
|
||||||
// if cursor is empty, why? do we have an invalid location
|
// if cursor is empty, why? do we have an invalid location
|
||||||
int message = R.string.empty_forecast_list;
|
int message = R.string.empty_forecast_list;
|
||||||
|
|||||||
@@ -18,15 +18,14 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="com.example.android.sunshine.app.ForecastFragment">
|
tools:context="com.example.android.sunshine.app.ForecastFragment">
|
||||||
<ListView
|
<android.support.v7.widget.RecyclerView
|
||||||
style="@style/ForecastListStyle"
|
style="@style/ForecastListStyle"
|
||||||
android:id="@+id/listview_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/listview_forecast_empty"
|
android:id="@+id/recyclerview_forecast_empty"
|
||||||
android:text="@string/empty_forecast_list"
|
android:text="@string/empty_forecast_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
@@ -19,15 +19,15 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:elevation="@dimen/appbar_elevation"
|
android:elevation="@dimen/appbar_elevation"
|
||||||
tools:context="com.example.android.sunshine.app.ForecastFragment">
|
tools:context="com.example.android.sunshine.app.ForecastFragment">
|
||||||
<ListView
|
<android.support.v7.widget.RecyclerView
|
||||||
style="@style/ForecastListStyle"
|
style="@style/ForecastListStyle"
|
||||||
android:id="@+id/listview_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" />
|
android:divider="@null" />
|
||||||
<!-- empty list -->
|
<!-- empty list -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/listview_forecast_empty"
|
android:id="@+id/recyclerview_forecast_empty"
|
||||||
android:text="@string/empty_forecast_list"
|
android:text="@string/empty_forecast_list"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
|||||||
Reference in New Issue
Block a user