Expanding CarDrawerActivity for nested navigation
- CarDrawerActivity now works with CarDrawerAdapter and subclasses to
display Drawer content. It includes a CarDrawerController that handles
nested navigation (it maintains a stack of CarDrawerAdapter's). Also
added progress-bar that can be displayed while loading the content for
next level of drawer items.
- Added CarDrawerAdapter and sublcasses CarDrawerListAdapter and
CarDrawerEmptyAdater for use by consumers of CarDrawerActivity.
Bug: 32019250
Test: Manually
Change-Id: I0e3ed0c2fc7734d596ee4ca21dfefc6e17e18897
diff --git a/car-stream-ui-lib/res/drawable-hdpi/ic_list_view_disable.png b/car-stream-ui-lib/res/drawable-hdpi/ic_list_view_disable.png
new file mode 100644
index 0000000..651ee62
--- /dev/null
+++ b/car-stream-ui-lib/res/drawable-hdpi/ic_list_view_disable.png
Binary files differ
diff --git a/car-stream-ui-lib/res/drawable-mdpi/ic_list_view_disable.png b/car-stream-ui-lib/res/drawable-mdpi/ic_list_view_disable.png
new file mode 100644
index 0000000..8de7968
--- /dev/null
+++ b/car-stream-ui-lib/res/drawable-mdpi/ic_list_view_disable.png
Binary files differ
diff --git a/car-stream-ui-lib/res/drawable-xhdpi/ic_list_view_disable.png b/car-stream-ui-lib/res/drawable-xhdpi/ic_list_view_disable.png
new file mode 100644
index 0000000..82adcb2
--- /dev/null
+++ b/car-stream-ui-lib/res/drawable-xhdpi/ic_list_view_disable.png
Binary files differ
diff --git a/car-stream-ui-lib/res/drawable-xxhdpi/ic_list_view_disable.png b/car-stream-ui-lib/res/drawable-xxhdpi/ic_list_view_disable.png
new file mode 100644
index 0000000..fc64935
--- /dev/null
+++ b/car-stream-ui-lib/res/drawable-xxhdpi/ic_list_view_disable.png
Binary files differ
diff --git a/car-stream-ui-lib/res/layout/car_drawer_activity.xml b/car-stream-ui-lib/res/layout/car_drawer_activity.xml
index 631240b..88524e0 100644
--- a/car-stream-ui-lib/res/layout/car_drawer_activity.xml
+++ b/car-stream-ui-lib/res/layout/car_drawer_activity.xml
@@ -35,7 +35,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="left"
- android:layout_marginEnd="@dimen/car_drawer_margin_right"
+ android:layout_marginEnd="@dimen/car_drawer_right_margin"
android:background="@color/car_card"
android:paddingTop="@dimen/lens_header_height" >
@@ -43,6 +43,15 @@
android:id="@+id/drawer_list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
+
+ <ProgressBar
+ android:id="@+id/drawer_progress"
+ android:layout_width="@dimen/car_drawer_progress_bar_size"
+ android:layout_height="@dimen/car_drawer_progress_bar_size"
+ android:layout_gravity="center"
+ android:indeterminate="true"
+ android:visibility="gone" />
+
</FrameLayout>
</android.support.v4.widget.DrawerLayout>
diff --git a/car-stream-ui-lib/res/layout/car_list_item_empty.xml b/car-stream-ui-lib/res/layout/car_list_item_empty.xml
new file mode 100644
index 0000000..0aaff22
--- /dev/null
+++ b/car-stream-ui-lib/res/layout/car_list_item_empty.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="@dimen/car_drawer_disabled_list_margin_side"
+ android:focusable="false"
+ android:orientation="vertical"
+ android:background="@drawable/car_list_item_background" >
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/car_list_item_icon_size"
+ android:layout_height="@dimen/car_list_item_icon_size"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="@dimen/car_drawer_disabled_list_icon_margin_top"
+ android:layout_marginBottom="@dimen/car_drawer_disabled_list_icon_margin_bottom" />
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/car_drawer_disabled_list_margin_side"
+ android:gravity="center"
+ style="@style/CarBody1" />
+</LinearLayout>
diff --git a/car-stream-ui-lib/res/layout/car_menu_list_item_normal.xml b/car-stream-ui-lib/res/layout/car_menu_list_item_normal.xml
new file mode 100644
index 0000000..1c14bdb
--- /dev/null
+++ b/car-stream-ui-lib/res/layout/car_menu_list_item_normal.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- NOTE: If you are changing anything here, you may need to update car_menu_list_item_small.xml.
+ DrawerItemViewHolder inflates one of these two layouts. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/car_list_item_height"
+ android:focusable="true"
+ android:orientation="horizontal"
+ android:background="@drawable/car_list_item_background" >
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/car_list_item_icon_size"
+ android:layout_height="@dimen/car_list_item_icon_size"
+ android:layout_marginRight="@dimen/car_list_item_icon_right_margin"
+ android:layout_gravity="center_vertical"
+ android:scaleType="centerCrop" />
+ <LinearLayout
+ android:id="@+id/text_container"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical" >
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/car_text_vertical_margin"
+ style="@style/CarBody1"
+ android:singleLine="true" />
+ <TextView
+ android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/CarBody2"
+ android:ellipsize="end"
+ android:singleLine="true" />
+ </LinearLayout>
+ <ImageView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/car_list_item_right_icon_size"
+ android:layout_height="@dimen/car_list_item_right_icon_size"
+ android:scaleType="fitCenter"
+ android:layout_marginEnd="@dimen/car_drawer_item_right_icon_margin_end"
+ android:layout_gravity="center_vertical"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/car-stream-ui-lib/res/layout/car_menu_list_item_small.xml b/car-stream-ui-lib/res/layout/car_menu_list_item_small.xml
new file mode 100644
index 0000000..a1da2b2
--- /dev/null
+++ b/car-stream-ui-lib/res/layout/car_menu_list_item_small.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<!-- NOTE: If you are changing anything here, you may need to update car_menu_list_item_normal.xml.
+ DrawerItemViewHolder inflates one of these two layouts. -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/car_list_item_height_small"
+ android:focusable="true"
+ android:orientation="horizontal"
+ android:background="@drawable/car_list_item_background" >
+ <ImageView
+ android:id="@+id/icon"
+ android:layout_width="@dimen/car_list_item_small_icon_size"
+ android:layout_height="@dimen/car_list_item_small_icon_size"
+ android:layout_marginRight="@dimen/car_list_item_icon_right_margin"
+ android:layout_gravity="center_vertical"
+ android:scaleType="centerCrop" />
+ <TextView
+ android:id="@+id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:layout_marginBottom="@dimen/car_text_vertical_margin"
+ style="@style/CarBody1"
+ android:singleLine="true" />
+ <ImageView
+ android:id="@+id/right_icon"
+ android:layout_width="@dimen/car_list_item_right_icon_size"
+ android:layout_height="@dimen/car_list_item_right_icon_size"
+ android:scaleType="fitCenter"
+ android:layout_marginEnd="@dimen/car_drawer_item_right_icon_margin_end"
+ android:layout_gravity="center_vertical"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/car-stream-ui-lib/res/values/dimens.xml b/car-stream-ui-lib/res/values/dimens.xml
index 67d5fbd..f350db7 100644
--- a/car-stream-ui-lib/res/values/dimens.xml
+++ b/car-stream-ui-lib/res/values/dimens.xml
@@ -46,4 +46,18 @@
<!-- The default size for the icons within the touch targets in car applications.. -->
<dimen name="stream_button_icon_size">36dp</dimen>
+
+ <!-- Size of progress-bar in Drawer -->
+ <dimen name="car_drawer_progress_bar_size">48dp</dimen>
+
+ <!-- NOTE: car-support defines a similarly named value, but the value varies by screen-size. We
+ do not want that -->
+ <dimen name="car_drawer_right_margin">96dp</dimen>
+
+ <dimen name="car_drawer_item_right_icon_margin_end">32dp</dimen>
+
+ <!-- Used by car_list_item_empty.xml -->
+ <dimen name="car_drawer_disabled_list_margin_side">16dp</dimen>
+ <dimen name="car_drawer_disabled_list_icon_margin_top">48dp</dimen>
+ <dimen name="car_drawer_disabled_list_icon_margin_bottom">22dp</dimen>
</resources>
diff --git a/car-stream-ui-lib/src/com/android/car/app/CarDrawerActivity.java b/car-stream-ui-lib/src/com/android/car/app/CarDrawerActivity.java
index 50de9b1..39e9838 100644
--- a/car-stream-ui-lib/src/com/android/car/app/CarDrawerActivity.java
+++ b/car-stream-ui-lib/src/com/android/car/app/CarDrawerActivity.java
@@ -22,27 +22,32 @@
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
-import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.View;
+import android.widget.ProgressBar;
import com.android.car.stream.ui.R;
+import java.util.Stack;
+
/**
* Common base Activity for car apps that need to present a Drawer.
* <p>
* This Activity manages the overall layout. To use it sub-classes need to:
* <ul>
- * <li>Provide the items for the Drawer by supplying a adapter to the PagedListView (see {@link
- * #getDrawerListView()}). The Adapter should ideally be based on {@link DrawerItemViewHolder}
- * since that produces items with the right layout and provides click-handling.</li>
+ * <li>Provide the root-items for the Drawer by implementing {@link #getRootAdapter()}.</li>
* <li>Add their main content to the container FrameLayout
* (with id = {@link #getContentContainerId()}_</li>
* </ul>
* This class will take care of drawer toggling and display.
* <p>
+ * The rootAdapter can implement nested-navigation, in its click-handling, by passing the
+ * CarDrawerAdapter for the next level to {@link #switchToAdapter(CarDrawerAdapter)}. This
+ * activity will maintain a stack of such adapters. When the user navigates up, it will pop the top
+ * adapter off and display its contents again.
+ * <p>
* Any Activity's based on this class need to set their theme to CarDrawerActivityTheme or a
* derivative.
* <p>
@@ -52,8 +57,10 @@
public abstract class CarDrawerActivity extends AppCompatActivity {
private static final float COLOR_SWITCH_SLIDE_OFFSET = 0.25f;
+ private final Stack<CarDrawerAdapter> mAdapterStack = new Stack<>();
private DrawerLayout mDrawerLayout;
private PagedListView mDrawerList;
+ private ProgressBar mProgressBar;
private View mDrawerContent;
private Toolbar mToolbar;
private ActionBarDrawerToggle mDrawerToggle;
@@ -66,37 +73,57 @@
mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
mDrawerContent = findViewById(R.id.drawer_content);
mDrawerList = (PagedListView)findViewById(R.id.drawer_list);
+ mProgressBar = (ProgressBar)findViewById(R.id.drawer_progress);
mToolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(mToolbar);
+
+ // Init drawer adapter stack.
+ CarDrawerAdapter rootAdapter = getRootAdapter();
+ mAdapterStack.push(rootAdapter);
+ mToolbar.setTitle(rootAdapter.getTitleResId());
+ mDrawerList.setAdapter(rootAdapter);
+
setupDrawerToggling();
}
/**
- * Get the DrawerLayout that this activity owns. Callers can perform operations like opening/
- * closing or adding listeners.
- *
- * @return DrawerLayout managed by this activity.
+ * @return Adapter for root content of the Drawer.
*/
- protected DrawerLayout getDrawerLayout() {
- return mDrawerLayout;
- }
+ protected abstract CarDrawerAdapter getRootAdapter();
/**
- * Get the PagedListView that will display the main content of the drawer. Sub-classes should
- * supply content via {@link PagedListView#setAdapter(RecyclerView.Adapter)}.
+ * Used to pass in next level of items to display in the Drawer, including updated title. It is
+ * pushed on top of the existing adapter in a stack. Navigating up from this level later will
+ * pop this adapter off and surface contents of the next adapter at the top of the stack (and
+ * its title).
*
- * @return PagedListView used to display main drawer content.
+ * @param adapter Adapter for next level of content in the drawer.
*/
- protected PagedListView getDrawerListView() {
- return mDrawerList;
+ protected final void switchToAdapter(CarDrawerAdapter adapter) {
+ mAdapterStack.push(adapter);
+ setTitleAndSwitchToAdapter(adapter);
}
/**
* Close the drawer if open.
*/
protected void closeDrawer() {
- mDrawerLayout.closeDrawer(Gravity.LEFT);
+ if (mDrawerLayout.isDrawerOpen(Gravity.LEFT)) {
+ mDrawerLayout.closeDrawer(Gravity.LEFT);
+ }
+ }
+
+ /**
+ * Used to switch between the Drawer PagedListView and the "loading" progress-bar while the next
+ * level's adapter contents are being fetched.
+ *
+ * @param enable If true, the progress-bar is displayed. If false, the Drawer PagedListView is
+ * added.
+ */
+ protected void showLoadingProgressBar(boolean enable) {
+ mDrawerList.setVisibility(enable ? View.INVISIBLE : View.VISIBLE);
+ mProgressBar.setVisibility(enable ? View.VISIBLE : View.GONE);
}
/**
@@ -127,7 +154,11 @@
@Override
public void onDrawerOpened(View drawerView) {}
@Override
- public void onDrawerClosed(View drawerView) {}
+ public void onDrawerClosed(View drawerView) {
+ // If drawer is closed for any reason, revert stack/drawer to initial root state.
+ cleanupStackAndShowRoot();
+ mDrawerList.getRecyclerView().scrollToPosition(0);
+ }
@Override
public void onDrawerStateChanged(int newState) {}
});
@@ -166,11 +197,41 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- // Delegate touches; It toobar handled them (e.g. menu icon tap), we return.
+ // Handle home-click and see if we can navigate up in the drawer.
+ if (item != null && item.getItemId() == android.R.id.home && maybeHandleUpClick()) {
+ return true;
+ }
+
+ // DrawerToggle gets next chance to handle up-clicks (and any other clicks).
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
+
+ private void setTitleAndSwitchToAdapter(CarDrawerAdapter adapter) {
+ mToolbar.setTitle(adapter.getTitleResId());
+ // NOTE: We don't use swapAdapter() since different levels in the Drawer may switch between
+ // car_menu_list_item_normal, car_menu_list_item_small and car_list_empty layouts.
+ mDrawerList.getRecyclerView().setAdapter(adapter);
+ mDrawerList.getRecyclerView().scrollToPosition(0);
+ }
+
+ private boolean maybeHandleUpClick() {
+ if (mAdapterStack.size() > 1) {
+ mAdapterStack.pop();
+ setTitleAndSwitchToAdapter(mAdapterStack.peek());
+ return true;
+ }
+ return false;
+ }
+
+ /** Clears stack down to root adapter and switches to root adapter. */
+ private void cleanupStackAndShowRoot() {
+ while (mAdapterStack.size() > 1) {
+ mAdapterStack.pop();
+ }
+ setTitleAndSwitchToAdapter(mAdapterStack.peek());
+ }
}
diff --git a/car-stream-ui-lib/src/com/android/car/app/CarDrawerAdapter.java b/car-stream-ui-lib/src/com/android/car/app/CarDrawerAdapter.java
new file mode 100644
index 0000000..166da14
--- /dev/null
+++ b/car-stream-ui-lib/src/com/android/car/app/CarDrawerAdapter.java
@@ -0,0 +1,42 @@
+package com.android.car.app;
+
+import android.support.annotation.StringRes;
+import android.support.car.ui.PagedListView;
+import android.support.v7.widget.RecyclerView;
+
+/**
+ * Base Adapter for displaying items in the CarDrawerActivity's Drawer which is a PagedListView.
+ * <p>
+ * Implementors must return the string resource for the title that will be displayed when displaying
+ * the contents of this adapter (see {@link #getTitleResId()}.
+ * <p>
+ * This class also takes care of implementing the PageListView.ItemCamp contract and subclasses
+ * should implement {@link #getActualItemCount()}.
+ */
+public abstract class CarDrawerAdapter extends RecyclerView.Adapter<DrawerItemViewHolder>
+ implements PagedListView.ItemCap {
+
+ private int mMaxItems = -1;
+
+ @Override
+ public final void setMaxItems(int maxItems) {
+ mMaxItems = maxItems;
+ }
+
+ @Override
+ public final int getItemCount() {
+ return mMaxItems >= 0 ? Math.min(mMaxItems, getActualItemCount()) : getActualItemCount();
+ }
+
+ /**
+ * @return Actual number of items in this adapter.
+ */
+ protected abstract int getActualItemCount();
+
+ /**
+ * @return String resource to display in the toolbar title when displaying this adapter's
+ * contents.
+ */
+ @StringRes
+ protected abstract int getTitleResId();
+}
diff --git a/car-stream-ui-lib/src/com/android/car/app/CarDrawerEmptyAdapter.java b/car-stream-ui-lib/src/com/android/car/app/CarDrawerEmptyAdapter.java
new file mode 100644
index 0000000..99c403b
--- /dev/null
+++ b/car-stream-ui-lib/src/com/android/car/app/CarDrawerEmptyAdapter.java
@@ -0,0 +1,51 @@
+package com.android.car.app;
+
+import android.content.Context;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.StringRes;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.car.stream.ui.R;
+
+/**
+ * Concrete subclass of {@link CarDrawerAdapter} to that displays a single "empty list" indicator.
+ */
+public class CarDrawerEmptyAdapter extends CarDrawerAdapter {
+ @StringRes
+ private final int mTitleResId;
+ private final Drawable mEmptyListDrawable;
+
+ public CarDrawerEmptyAdapter(Context context, @StringRes int titleResId) {
+ mTitleResId = titleResId;
+ final int iconColor = context.getColor(R.color.car_tint);
+ mEmptyListDrawable = context.getDrawable(R.drawable.ic_list_view_disable);
+ mEmptyListDrawable.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
+ }
+
+ @Override
+ public DrawerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.car_list_item_empty, parent, false);
+ return new DrawerItemViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(DrawerItemViewHolder holder, int position) {
+ holder.getTitle().setText(null);
+ holder.getIcon().setImageDrawable(mEmptyListDrawable);
+ holder.setItemClickListener(null);
+ }
+
+ @Override
+ protected int getActualItemCount() {
+ return 1;
+ }
+
+ @Override
+ protected int getTitleResId() {
+ return mTitleResId;
+ }
+}
diff --git a/car-stream-ui-lib/src/com/android/car/app/CarDrawerListAdapter.java b/car-stream-ui-lib/src/com/android/car/app/CarDrawerListAdapter.java
new file mode 100644
index 0000000..7a2c052
--- /dev/null
+++ b/car-stream-ui-lib/src/com/android/car/app/CarDrawerListAdapter.java
@@ -0,0 +1,56 @@
+package com.android.car.app;
+
+import android.support.annotation.LayoutRes;
+import android.support.car.ui.PagedListView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.car.stream.ui.R;
+
+/**
+ * Variant of {@link CarDrawerAdapter} for displaying a list of items that support clicks.
+ * <p>
+ * Subclasses should implement:
+ * <ul>
+ * <li>{@link #populateViewHolder(DrawerItemViewHolder, int)} to actually populate the
+ * drawer-item.</li>
+ * <li>{@link #getTitleResId()} to set the string to display when the Drawer is displaying this
+ * adapter's contents.</li>
+ * <li>{@link #getActualItemCount()} to return the actual number of items in the adapter (since
+ * {@link #getItemCount()} needs to honor {@link PagedListView.ItemCap}.</li>
+ * <li>{@link #onItemClick(int)} to handle clicks on items. To load a sub-level of items, the
+ * handler may call {@link CarDrawerActivity#switchToAdapter(CarDrawerAdapter)} to load
+ * the next level of items.</li>
+ * </ul>
+ */
+public abstract class CarDrawerListAdapter extends CarDrawerAdapter
+ implements DrawerItemClickListener {
+ @LayoutRes
+ private final int mItemLayoutResId;
+
+ protected CarDrawerListAdapter(boolean useNormalLayout) {
+ mItemLayoutResId = useNormalLayout ?
+ R.layout.car_menu_list_item_normal : R.layout.car_menu_list_item_small;
+ }
+
+ @Override
+ public final DrawerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View view = LayoutInflater.from(parent.getContext())
+ .inflate(mItemLayoutResId, parent, false);
+ return new DrawerItemViewHolder(view);
+ }
+
+ @Override
+ public final void onBindViewHolder(DrawerItemViewHolder holder, int position) {
+ holder.setItemClickListener(this);
+ populateViewHolder(holder, position);
+ }
+
+ /**
+ * Subclasses should set all elements in {@code holder} to populate the drawer-item.
+ * If some element is not used, it should be nulled out since these ViewHolder/View's are
+ * recycled.
+ */
+ protected abstract void populateViewHolder(DrawerItemViewHolder holder, int position);
+}
\ No newline at end of file
diff --git a/car-stream-ui-lib/src/com/android/car/app/DrawerItemViewHolder.java b/car-stream-ui-lib/src/com/android/car/app/DrawerItemViewHolder.java
index 38524cf..55eedc5 100644
--- a/car-stream-ui-lib/src/com/android/car/app/DrawerItemViewHolder.java
+++ b/car-stream-ui-lib/src/com/android/car/app/DrawerItemViewHolder.java
@@ -16,84 +16,77 @@
package com.android.car.app;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewStub;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.car.stream.ui.R;
/**
- * Re-usable ViewHolder that inflates car_menu_list_item.xml layout for use in the Drawer
- * PagedListView (see {@link CarDrawerActivity#getDrawerListView()}.
- * <p>
- * Clients should call {@link #create(ViewGroup, DrawerItemClickListener)} in their RecyclerView
- * Adapter's onCreateViewHolder.
- * <p>
- * A {@link DrawerItemClickListener} can be provided to handle clicks on specific items.
+ * Re-usable ViewHolder for displaying items in the Drawer PagedListView.
*/
public class DrawerItemViewHolder extends RecyclerView.ViewHolder {
private final ImageView mIcon;
private final TextView mTitle;
private final TextView mText;
- private final ViewStub mRightItem;
+ private final ImageView mRightIcon;
- /**
- * Inflates car_menu_list_item.xml layout and wraps it in a DrawerItemViewHolder.
- *
- * @param parent Parent ViewGroup for created views.
- * @param listener Optional click listener to handle clicks.
- * @return DrawerItemViewHolder wrapping the inflated view.
- */
- public static DrawerItemViewHolder create(ViewGroup parent,
- @Nullable DrawerItemClickListener listener) {
- View view = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.car_menu_list_item, parent, false);
- return new DrawerItemViewHolder(view, listener);
+ DrawerItemViewHolder(View view) {
+ super(view);
+ mIcon = (ImageView)view.findViewById(R.id.icon);
+ mTitle = (TextView)view.findViewById(R.id.title);
+ if (mIcon == null || mTitle == null) {
+ throw new IllegalArgumentException("Missing required elements in provided view!");
+ }
+ // Next two are optional and may be null.
+ mText = (TextView)view.findViewById(R.id.text);
+ mRightIcon = (ImageView)view.findViewById(R.id.right_icon);
}
/**
- * @return Icon ImageView from inflated car_menu_list_item.xml layout.
+ * @return Icon ImageView from inflated layout.
*/
+ @NonNull
public ImageView getIcon() {
return mIcon;
}
/**
- * @return Main title TextView inflated from car_menu_list_item.xml layout.
+ * @return Main title TextView from inflated layout.
*/
+ @NonNull
public TextView getTitle() {
return mTitle;
}
/**
- * @return Main text TextView from inflated car_menu_list_item.xml layout.
+ * @return Main text TextView from inflated layout. May be null.
*/
+ @Nullable
public TextView getText() {
return mText;
}
/**
- * @return Right-Item ViewStub from inflated car_menu_list_item.xml layout.
+ * @return Right-Icon ImageView from inflated layout. May be null.
*/
- public ViewStub getRightItem() {
- return mRightItem;
+ @Nullable
+ public ImageView getRightIcon() {
+ return mRightIcon;
}
- private DrawerItemViewHolder(View view, @Nullable DrawerItemClickListener listener) {
- super(view);
- mIcon = (ImageView)view.findViewById(R.id.icon);
- mTitle = (TextView)view.findViewById(R.id.title);
- mText = (TextView)view.findViewById(R.id.text);
- mRightItem = (ViewStub)view.findViewById(R.id.right_item);
+ /**
+ * Set click-listener on the view wrapped by this ViewHolder. For now only used by
+ * {@link CarDrawerListAdapter}.
+ */
+ void setItemClickListener(@Nullable DrawerItemClickListener listener) {
if (listener != null) {
- view.setOnClickListener((unusedView) -> {
- listener.onItemClick(getAdapterPosition());
- });
+ itemView.setOnClickListener((unusedView) -> listener.onItemClick(getAdapterPosition()));
+ } else {
+ itemView.setOnClickListener(null);
}
}
}