public abstract class

ListItem<VH extends ListItem.ViewHolder>

extends java.lang.Object

 java.lang.Object

↳androidx.car.widget.ListItem<VH>

Subclasses:

SubheaderListItem, ActionListItem, SeekbarListItem, RadioButtonListItem, TextListItem, SwitchListItem

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

Definition of items that can be inserted into ListItemAdapter.

Summary

Constructors
publicListItem()

Methods
public final voidaddViewBinder(ListItem.ViewBinder<ListItem.ViewHolder> binder)

Same as ListItem.addViewBinder(ListItem.ViewBinder, ListItem.ViewBinder) when cleanUp ViewBinder is null.

public final voidaddViewBinder(ListItem.ViewBinder<ListItem.ViewHolder> binder, ListItem.ViewBinder<ListItem.ViewHolder> cleanUp)

Adds ListItem.ViewBinder to interact with sub-views in ListItem.ViewHolder.

public booleangetShowDivider()

Returns whether or not the divider that comes after this ListItem should be shown.

public abstract intgetViewType()

Classes that extends ListItem should register its view type in ListItemAdapter.registerListItemViewType(int, int, Function).

protected booleanisDirty()

protected voidmarkClean()

Marks this item as not dirty.

protected voidmarkDirty()

Marks this item as dirty so ListItem.resolveDirtyState() is required in next bind() call.

protected abstract voidonBind(ListItem.ViewHolder viewHolder)

Binds this ListItem to viewHolder by applying data in ListItem to sub-views.

public booleanremoveViewBinder(ListItem.ViewBinder<ListItem.ViewHolder> binder)

Removes the first occurrence of the specified item.

protected abstract voidresolveDirtyState()

Does the work that moves the ListItem from dirty state to clean state, i.e.

public abstract voidsetEnabled(boolean enabled)

Sets the enabled state of the bound ListItem.ViewHolder.

public voidsetShowDivider(boolean showDivider)

Whether to show the item divider coming after this ListItem.

from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public ListItem()

Methods

public abstract int getViewType()

Classes that extends ListItem should register its view type in ListItemAdapter.registerListItemViewType(int, int, Function).

Returns:

type of this ListItem.

public abstract void setEnabled(boolean enabled)

Sets the enabled state of the bound ListItem.ViewHolder.

All visible children views of ViewHolder should be set to enabled. Caller is responsible for notifying ListItemAdapter about data change.

Disabled items are usually styled at 50% opacity. Consider similar styling for consistency.

protected void markDirty()

Marks this item as dirty so ListItem.resolveDirtyState() is required in next bind() call.

This method should be called in each setter.

protected void markClean()

Marks this item as not dirty. No need to call ListItem.resolveDirtyState() in next bind().

protected boolean isDirty()

Returns:

true if next bind() should call ListItem.resolveDirtyState().

public void setShowDivider(boolean showDivider)

Whether to show the item divider coming after this ListItem.

Note: For this to work, one must invoke PagedListView.setDividerVisibilityManager(adapter for ListItemAdapter and have dividers enabled on PagedListView.

public boolean getShowDivider()

Returns whether or not the divider that comes after this ListItem should be shown.

Returns:

true if the divider should be shown. Defaults to true.

protected abstract void resolveDirtyState()

Does the work that moves the ListItem from dirty state to clean state, i.e. the work required the first time this ListItem binds to ListItem.ViewHolder. This method will transition ListItem to clean state. ListItem in clean state should move to dirty state when it is modified by calling ListItem.markDirty().

protected abstract void onBind(ListItem.ViewHolder viewHolder)

Binds this ListItem to viewHolder by applying data in ListItem to sub-views. Assume ListItem.ViewHolder.cleanUp() has already been invoked.

public final void addViewBinder(ListItem.ViewBinder<ListItem.ViewHolder> binder)

Same as ListItem.addViewBinder(ListItem.ViewBinder, ListItem.ViewBinder) when cleanUp ViewBinder is null.

Parameters:

binder: to interact with subviews in ViewHolder.

See also: ListItem.addViewBinder(ListItem.ViewBinder, ListItem.ViewBinder)

public final void addViewBinder(ListItem.ViewBinder<ListItem.ViewHolder> binder, ListItem.ViewBinder<ListItem.ViewHolder> cleanUp)

Adds ListItem.ViewBinder to interact with sub-views in ListItem.ViewHolder. These ViewBinders will always be applied after ListItem.onBind(VH).

To interact with a foobar sub-view in ViewHolder, make sure to first set its visibility, or call setFoobar() setter method.

Example:

 
 TextListItem item = new TextListItem(context);
 item.setTitle("title");
 item.addViewBinder((viewHolder) -> {
     viewHolder.getTitle().doFoobar();
 }, (viewHolder) -> {
     viewHolder.getTitle().revertFoobar();
 });
 
 

Parameters:

binder: to interact with subviews in ViewHolder.
cleanUp: view binder to revert the effect of binder. cleanUp binders will be stored in ListItem.ViewHolder and should be invoked via ListItem.ViewHolder.cleanUp() before ViewHolder is recycled. This is to avoid changed made to ViewHolder lingers around when ViewHolder is recycled. Pass in null to skip.

public boolean removeViewBinder(ListItem.ViewBinder<ListItem.ViewHolder> binder)

Removes the first occurrence of the specified item.

Parameters:

binder: to be removed.

Returns:

true if binder exists. false otherwise.

Source

/*
 * Copyright 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.widget;

import android.view.View;

import androidx.annotation.Nullable;
import androidx.car.uxrestrictions.OnUxRestrictionsChangedListener;
import androidx.recyclerview.widget.RecyclerView;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * Definition of items that can be inserted into {@link ListItemAdapter}.
 *
 * @param <VH> ViewHolder that extends {@link ListItem.ViewHolder}.
 */
public abstract class ListItem<VH extends ListItem.ViewHolder> {

    // Whether the item should calculate view layout params. This usually happens when the item is
    // updated after bind() is called. Calling bind() resets to false.
    private boolean mDirty;

    // Tag for indicating whether to show the divider.
    private boolean mShowDivider = true;

    private final List<ViewBinder<VH>> mCustomBinders = new ArrayList<>();
    // Stores ViewBinders to revert customization. Does not guarantee to 1:1 match ViewBinders
    // in mCustomerBinders.
    private final List<ViewBinder<VH>> mCustomBinderCleanUps = new ArrayList<>();

    /**
     * Classes that extends {@code ListItem} should register its view type in
     * {@link ListItemAdapter#registerListItemViewType(int, int, Function)}.
     *
     * @return type of this ListItem.
     */
    public abstract int getViewType();

    /**
     * Called when ListItem is bound to its ViewHolder.
     */
    final void bind(VH viewHolder) {
        // Attempt to clean up custom view binder from previous item (if any).
        // Then save the clean up binders for next item.
        viewHolder.cleanUp();
        for (ViewBinder cleanUp : mCustomBinderCleanUps) {
            viewHolder.addCleanUp(cleanUp);
        }

        if (isDirty()) {
            resolveDirtyState();
            markClean();
        }
        onBind(viewHolder);

        // Custom view binders are applied after view layout.
        for (ViewBinder<VH> binder: mCustomBinders) {
            binder.bind(viewHolder);
        }
    }

    /**
     * Sets the enabled state of the bound {@link ViewHolder}.
     *
     * <p>All visible children views of {@code ViewHolder} should be set to {@code enabled}. Caller
     * is responsible for notifying {@link ListItemAdapter} about data change.
     *
     * <p>Disabled items are usually styled at 50% opacity. Consider similar styling for
     * consistency.
     */
    public abstract void setEnabled(boolean enabled);

    /**
     * Marks this item as dirty so {@link #resolveDirtyState()} is required in next bind() call.
     *
     * <p>This method should be called in each setter.
     */
    protected void markDirty() {
        mDirty = true;
    }

    /**
     * Marks this item as not dirty. No need to call {@link #resolveDirtyState()} in next bind().
     */
    protected void markClean() {
        mDirty = false;
    }

    /**
     * @return {@code true} if next bind() should call {@link #resolveDirtyState()}.
     */
    protected boolean isDirty() {
        return mDirty;
    }

    /**
     * Whether to show the item divider coming after this {@code ListItem}.
     *
     * <p>Note: For this to work, one must invoke
     * {@code PagedListView.setDividerVisibilityManager(adapter} for {@link ListItemAdapter} and
     * have dividers enabled on {@link PagedListView}.
     */
    public void setShowDivider(boolean showDivider) {
        mShowDivider = showDivider;
        markDirty();
    }

    /**
     * Returns whether or not the divider that comes after this ListItem should be shown.
     *
     * @return {@code true} if the divider should be shown. Defaults to {@code true}.
     */
    public boolean getShowDivider() {
        return mShowDivider;
    }

    /**
     * Does the work that moves the ListItem from dirty state to clean state, i.e. the work required
     * the first time this ListItem {@code bind}s to {@link ListItem.ViewHolder}.
     * This method will transition ListItem to clean state. ListItem in clean state should move to
     * dirty state when it is modified by calling {@link #markDirty()}.
     */
    protected abstract void resolveDirtyState();

    /**
     * Binds this ListItem to {@code viewHolder} by applying data in ListItem to sub-views.
     * Assume {@link ViewHolder#cleanUp()} has already been invoked.
     */
    protected abstract void onBind(VH viewHolder);

    /**
     * Same as {@link #addViewBinder(ViewBinder, ViewBinder)} when {@code cleanUp} ViewBinder
     * is null.
     *
     * @param binder to interact with subviews in {@code ViewHolder}.
     *
     * @see #addViewBinder(ViewBinder, ViewBinder)
     */
    public final void addViewBinder(ViewBinder<VH> binder) {
        addViewBinder(binder, null);
    }

    /**
     * Adds {@link ViewBinder} to interact with sub-views in {@link ViewHolder}. These ViewBinders
     * will always be applied after {@link #onBind(ViewHolder)}.
     *
     * <p>To interact with a foobar sub-view in {@code ViewHolder}, make sure to first set its
     * visibility, or call setFoobar() setter method.
     *
     * <p>Example:
     * <pre>
     * {@code
     * TextListItem item = new TextListItem(context);
     * item.setTitle("title");
     * item.addViewBinder((viewHolder) -> {
     *     viewHolder.getTitle().doFoobar();
     * }, (viewHolder) -> {
     *     viewHolder.getTitle().revertFoobar();
     * });
     * }
     * </pre>
     *
     * @param binder to interact with subviews in {@code ViewHolder}.
     * @param cleanUp view binder to revert the effect of {@code binder}. cleanUp binders will be
     *                 stored in {@link ListItem.ViewHolder} and should be invoked via
     *                 {@link ViewHolder#cleanUp()} before {@code ViewHolder} is recycled.
     *                 This is to avoid changed made to ViewHolder lingers around when ViewHolder is
     *                 recycled. Pass in null to skip.
     */
    public final void addViewBinder(ViewBinder<VH> binder, @Nullable ViewBinder<VH> cleanUp) {
        mCustomBinders.add(binder);
        if (cleanUp != null) {
            mCustomBinderCleanUps.add(cleanUp);
        }
        markDirty();
    }

    /**
     * Removes the first occurrence of the specified item.
     *
     * @param binder to be removed.
     * @return {@code true} if {@code binder} exists. {@code false} otherwise.
     */
    public boolean removeViewBinder(ViewBinder<VH> binder) {
        return mCustomBinders.remove(binder);
    }

    /**
     * Functional interface to provide a way to interact with views in {@code ViewHolder}.
     * {@code ListItem} calls all added ViewBinders when it {@code bind}s to {@code ViewHolder}.
     *
     * @param <VH> class that extends {@link RecyclerView.ViewHolder}.
     */
    public interface ViewBinder<VH> {
        /**
         * Provides a way to interact with views in view holder.
         */
        void bind(VH viewHolder);
    }

    /**
     * ViewHolder that supports {@link ViewBinder}.
     */
    public abstract static class ViewHolder extends RecyclerView.ViewHolder implements
            OnUxRestrictionsChangedListener {
        private final List<ViewBinder> mCleanUps = new ArrayList<>();

        public ViewHolder(View itemView) {
            super(itemView);
        }

        /**
         * Removes customization from previous ListItem. Intended to be used when this ViewHolder is
         * bound to a ListItem.
         */
        public final void cleanUp() {
            for (ViewBinder binder : mCleanUps) {
                binder.bind(this);
            }
        }

        /**
         * Stores clean up ViewBinders that will be called in {@code cleanUp()}.
         */
        public final void addCleanUp(@Nullable ViewBinder<ViewHolder> cleanUp) {
            if (cleanUp != null) {
                mCleanUps.add(cleanUp);
            }
        }
    }
}