public abstract class

CarDrawerAdapter

extends RecyclerView.Adapter<DrawerItemViewHolder>

implements PagedListView.ItemCap

 java.lang.Object

androidx.recyclerview.widget.RecyclerView.Adapter<DrawerItemViewHolder>

↳androidx.car.drawer.CarDrawerAdapter

Gradle dependencies

compile group: 'androidx.car', name: 'car', version: '1.0.0-alpha7'

  • groupId: androidx.car
  • artifactId: car
  • version: 1.0.0-alpha7

Artifact androidx.car:car:1.0.0-alpha7 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.car:car com.android.support:car

Overview

Base adapter for displaying items in the car navigation drawer, which uses a PagedListView.

Subclasses can optionally set the title that will be displayed when displaying the contents of the drawer via CarDrawerAdapter.setTitle(CharSequence). The title can be updated at any point later on. The title of the root adapter will also be the main title showed in the toolbar when the drawer is closed. See CarDrawerController.setRootAdapter(CarDrawerAdapter) for more information.

This class also takes care of implementing the PageListView.ItemCamp contract and subclasses should implement CarDrawerAdapter.getActualItemCount().

To enable support for CarUxRestrictions, call CarDrawerAdapter.start() in your Activity's , and CarDrawerAdapter.stop() in .

Summary

Constructors
protectedCarDrawerAdapter(Context context, boolean showDisabledListOnEmpty)

Methods
public voidcleanup()

Called when this adapter has been popped off the stack and is no longer needed.

protected abstract intgetActualItemCount()

Returns the absolute number of items that can be displayed in the list.

public abstract intgetItemCount()

Returns the total number of items in the data set held by the adapter.

public intgetItemViewType(int position)

Return the view type of the item at position for the purposes of view recycling.

public abstract voidonBindViewHolder(RecyclerView.ViewHolder holder, int position)

Called by RecyclerView to display the data at the specified position.

public abstract RecyclerView.ViewHolderonCreateViewHolder(ViewGroup parent, int viewType)

Called when RecyclerView needs a new RecyclerView.ViewHolder of the given type to represent an item.

protected abstract voidpopulateViewHolder(DrawerItemViewHolder holder, int position)

Subclasses should set all elements in holder to populate the drawer-item.

public final voidsetMaxItems(int maxItems)

public final voidsetTitle(java.lang.CharSequence title)

Updates the title to display in the toolbar for this Adapter.

public voidstart()

Enables support for CarUxRestrictions.

public voidstop()

Disables support for CarUxRestrictions, and frees up resources.

protected booleanusesSmallLayout(int position)

Used to indicate the layout used for the Drawer item at given position.

from RecyclerView.Adapter<VH>bindViewHolder, createViewHolder, findRelativeAdapterPositionIn, getItemId, getStateRestorationPolicy, hasObservers, hasStableIds, notifyDataSetChanged, notifyItemChanged, notifyItemChanged, notifyItemInserted, notifyItemMoved, notifyItemRangeChanged, notifyItemRangeChanged, notifyItemRangeInserted, notifyItemRangeRemoved, notifyItemRemoved, onAttachedToRecyclerView, onBindViewHolder, onDetachedFromRecyclerView, onFailedToRecycleView, onViewAttachedToWindow, onViewDetachedFromWindow, onViewRecycled, registerAdapterDataObserver, setHasStableIds, setStateRestorationPolicy, unregisterAdapterDataObserver
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

protected CarDrawerAdapter(Context context, boolean showDisabledListOnEmpty)

Methods

public void start()

Enables support for CarUxRestrictions.

This method can be called from Activity's , or at the time of construction.

This method must be accompanied with a matching CarDrawerAdapter.stop() to avoid leak.

public void stop()

Disables support for CarUxRestrictions, and frees up resources.

This method should be called from Activity's , or at the time of this adapter being discarded.

public final void setTitle(java.lang.CharSequence title)

Updates the title to display in the toolbar for this Adapter.

public final void setMaxItems(int maxItems)

public abstract int getItemCount()

Returns the total number of items in the data set held by the adapter.

Returns:

The total number of items in this adapter.

protected abstract int getActualItemCount()

Returns the absolute number of items that can be displayed in the list.

A class should implement this method to supply the number of items to be displayed. Returning 0 from this method will cause an empty list icon to be displayed in the drawer.

A class should override this method rather than CarDrawerAdapter.getItemCount() because that method is handling the logic of when to display the empty list icon. It will return 1 when CarDrawerAdapter.getActualItemCount() returns 0.

Returns:

The number of items to be displayed in the list.

public int getItemViewType(int position)

Return the view type of the item at position for the purposes of view recycling.

The default implementation of this method returns 0, making the assumption of a single view type for the adapter. Unlike ListView adapters, types need not be contiguous. Consider using id resources to uniquely identify item view types.

Parameters:

position: position to query

Returns:

integer value identifying the type of the view needed to represent the item at position. Type codes need not be contiguous.

protected boolean usesSmallLayout(int position)

Used to indicate the layout used for the Drawer item at given position. Subclasses can override this to use normal layout which includes text element below title.

A small layout is presented by the layout R.layout.car_drawer_list_item_small. Otherwise, the layout R.layout.car_drawer_list_item_normal will be used.

Parameters:

position: Adapter position of item.

Returns:

Whether the item at this position will use a small layout (default) or normal layout.

public abstract RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)

Called when RecyclerView needs a new RecyclerView.ViewHolder of the given type to represent an item.

This new ViewHolder should be constructed with a new View that can represent the items of the given type. You can either create a new View manually or inflate it from an XML layout file.

The new ViewHolder will be used to display items of the adapter using RecyclerView.Adapter. Since it will be re-used to display different items in the data set, it is a good idea to cache references to sub views of the View to avoid unnecessary View calls.

Parameters:

parent: The ViewGroup into which the new View will be added after it is bound to an adapter position.
viewType: The view type of the new View.

Returns:

A new ViewHolder that holds a View of the given view type.

See also: RecyclerView.Adapter.getItemViewType(int), RecyclerView.Adapter

public abstract void onBindViewHolder(RecyclerView.ViewHolder holder, int position)

Called by RecyclerView to display the data at the specified position. This method should update the contents of the RecyclerView.ViewHolder.itemView to reflect the item at the given position.

Note that unlike , RecyclerView will not call this method again if the position of the item changes in the data set unless the item itself is invalidated or the new position cannot be determined. For this reason, you should only use the position parameter while acquiring the related data item inside this method and should not keep a copy of it. If you need the position of an item later on (e.g. in a click listener), use RecyclerView.ViewHolder.getBindingAdapterPosition() which will have the updated adapter position. Override RecyclerView.Adapter instead if Adapter can handle efficient partial bind.

Parameters:

holder: The ViewHolder which should be updated to represent the contents of the item at the given position in the data set.
position: The position of the item within the adapter's data set.

protected abstract void populateViewHolder(DrawerItemViewHolder holder, int position)

Subclasses should set all elements in holder to populate the drawer-item. If some element is not used, it should be nulled out since these ViewHolder/View's are recycled.

public void cleanup()

Called when this adapter has been popped off the stack and is no longer needed. Subclasses can override to do any necessary cleanup.

Source

/*
 * 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.
 */

package androidx.car.drawer;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.car.R;
import androidx.car.util.CarUxRestrictionsHelper;
import androidx.car.uxrestrictions.CarUxRestrictions;
import androidx.car.widget.PagedListView;
import androidx.recyclerview.widget.RecyclerView;

/**
 * Base adapter for displaying items in the car navigation drawer, which uses a
 * {@link PagedListView}.
 *
 * <p>Subclasses can optionally set the title that will be displayed when displaying the contents
 * of the drawer via {@link #setTitle(CharSequence)}. The title can be updated at any point later
 * on. The title of the root adapter will also be the main title showed in the toolbar when the
 * drawer is closed. See {@link CarDrawerController#setRootAdapter(CarDrawerAdapter)} for more
 * information.
 *
 * <p>This class also takes care of implementing the PageListView.ItemCamp contract and subclasses
 * should implement {@link #getActualItemCount()}.
 *
 * <p>To enable support for {@link CarUxRestrictions}, call {@link #start()} in your
 * {@code Activity}'s {@link android.app.Activity#onCreate(Bundle)}, and {@link #stop()} in
 * {@link Activity#onStop()}.
 */
public abstract class CarDrawerAdapter extends RecyclerView.Adapter<DrawerItemViewHolder>
        implements PagedListView.ItemCap {
    private final boolean mShowDisabledListOnEmpty;
    private final Drawable mEmptyListDrawable;
    private int mMaxItems = PagedListView.ItemCap.UNLIMITED;
    private CharSequence mTitle;
    private TitleChangeListener mTitleChangeListener;

    private final CarUxRestrictionsHelper mUxRestrictionsHelper;
    private CarUxRestrictions mCurrentUxRestrictions;

    @LayoutRes private final int mSmallLayoutResId;
    @LayoutRes private final int mNormalLayoutResId;

    /**
     * Enables support for {@link CarUxRestrictions}.
     *
     * <p>This method can be called from {@code Activity}'s {@link Activity#onStart()}, or at the
     * time of construction.
     *
     * <p>This method must be accompanied with a matching {@link #stop()} to avoid leak.
     */
    public void start() {
        mUxRestrictionsHelper.start();
    }

    /**
     * Disables support for {@link CarUxRestrictions}, and frees up resources.
     *
     * <p>This method should be called from {@code Activity}'s {@link Activity#onStop()}, or at the
     * time of this adapter being discarded.
     */
    public void stop() {
        mUxRestrictionsHelper.stop();
    }

    /**
     * Interface for a class that will be notified a new title has been set on this adapter.
     */
    interface TitleChangeListener {
        /**
         * Called when {@link #setTitle(CharSequence)} has been called and the title has been
         * changed.
         */
        void onTitleChanged(@Nullable CharSequence newTitle);
    }

    protected CarDrawerAdapter(Context context, boolean showDisabledListOnEmpty) {
        mShowDisabledListOnEmpty = showDisabledListOnEmpty;

        mEmptyListDrawable = context.getDrawable(R.drawable.ic_list_view_disable);
        mEmptyListDrawable.setColorFilter(context.getColor(R.color.car_tint),
                PorterDuff.Mode.SRC_IN);

        TypedValue outValue = new TypedValue();
        Resources.Theme theme = context.getTheme();

        mSmallLayoutResId = theme.resolveAttribute(R.attr.drawerSmallLayoutId, outValue, true)
                ? outValue.resourceId
                : R.layout.car_drawer_list_item_small;
        mNormalLayoutResId = theme.resolveAttribute(R.attr.drawerNormalLayoutId, outValue, true)
                ? outValue.resourceId
                : R.layout.car_drawer_list_item_normal;

        mUxRestrictionsHelper =
                new CarUxRestrictionsHelper(context, carUxRestrictions -> {
                    mCurrentUxRestrictions = new CarUxRestrictions(carUxRestrictions);
                    notifyDataSetChanged();
                });
    }

    /** Returns the title set via {@link #setTitle(CharSequence)}. */
    CharSequence getTitle() {
        return mTitle;
    }

    /** Updates the title to display in the toolbar for this Adapter. */
    public final void setTitle(@Nullable CharSequence title) {
        mTitle = title;

        if (mTitleChangeListener != null) {
            mTitleChangeListener.onTitleChanged(mTitle);
        }
    }

    /** Sets a listener to be notified whenever the title of this adapter has been changed. */
    void setTitleChangeListener(@Nullable TitleChangeListener listener) {
        mTitleChangeListener = listener;
    }

    @Override
    public final void setMaxItems(int maxItems) {
        mMaxItems = maxItems;
    }

    @Override
    public final int getItemCount() {
        if (shouldShowDisabledListItem()) {
            return 1;
        }
        return mMaxItems >= 0 ? Math.min(mMaxItems, getActualItemCount()) : getActualItemCount();
    }

    /**
     * Returns the absolute number of items that can be displayed in the list.
     *
     * <p>A class should implement this method to supply the number of items to be displayed.
     * Returning 0 from this method will cause an empty list icon to be displayed in the drawer.
     *
     * <p>A class should override this method rather than {@link #getItemCount()} because that
     * method is handling the logic of when to display the empty list icon. It will return 1 when
     * {@link #getActualItemCount()} returns 0.
     *
     * @return The number of items to be displayed in the list.
     */
    protected abstract int getActualItemCount();

    @Override
    public final int getItemViewType(int position) {
        if (shouldShowDisabledListItem()) {
            return R.layout.car_drawer_list_item_empty;
        }

        return usesSmallLayout(position)
                ? mSmallLayoutResId
                : mNormalLayoutResId;
    }

    /**
     * Used to indicate the layout used for the Drawer item at given position. Subclasses can
     * override this to use normal layout which includes text element below title.
     *
     * <p>A small layout is presented by the layout {@code R.layout.car_drawer_list_item_small}.
     * Otherwise, the layout {@code R.layout.car_drawer_list_item_normal} will be used.
     *
     * @param position Adapter position of item.
     * @return Whether the item at this position will use a small layout (default) or normal layout.
     */
    protected boolean usesSmallLayout(int position) {
        return true;
    }

    @Override
    public final DrawerItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
        return new DrawerItemViewHolder(view);
    }

    @Override
    public final void onBindViewHolder(DrawerItemViewHolder holder, int position) {
        // Car may not be initialized thus current UXR will not be available.
        if (mCurrentUxRestrictions != null) {
            holder.onUxRestrictionsChanged(mCurrentUxRestrictions);
        }

        if (shouldShowDisabledListItem()) {
            holder.getTitleView().setText(null);
            holder.getIconView().setImageDrawable(mEmptyListDrawable);
        } else {
            populateViewHolder(holder, position);
        }
    }

    /**
     * Whether or not this adapter should be displaying an empty list icon. The icon is shown if it
     * has been configured to show and there are no items to be displayed.
     */
    private boolean shouldShowDisabledListItem() {
        return mShowDisabledListOnEmpty && getActualItemCount() == 0;
    }

    /**
     * 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);

    /**
     * Called when this adapter has been popped off the stack and is no longer needed. Subclasses
     * can override to do any necessary cleanup.
     */
    public void cleanup() {}
}