This tutorial is intended to go over a basic implementation of lists in the Chrome on Android MVC framework. If you're not sure what MVC is, see Additional Resources.
In this example we'll be creating a simple menu list where each list item consists of an icon and label.
The file structure of our component will be the following:
This class will own the ModelListAdapter
that knows how to show PropertyModels
. In this example we'll be combining the responsibilities of what would otherwise be the coordinator and mediator for simplicity.
public class SimpleMenuCoordinator { private SimpleMenuMediator mMediator; public SimpleMenuCoordinator(Context context, ListView listView) { ModelList listItems = new ModelList(); // Once this is attached to the ListView, there is no need to hold a reference to it. ModelListAdapter adapter = new ModelListAdapter(listItems); // If this is a heterogeneous list, register more than one type. adapter.registerType( ListItemType.DEFAULT, () -> LayoutInflater.from(context).inflate(R.layout.simple_menu_item, null), SimpleMenuItemViewBinder::bind); listView.setAdapter(adapter); mMediator = new SimpleMenuMediator(context, listItems); } }
This class is responsible for pushing updates into the ModelList
. Updates to that object are automatically pushed and bound to the list view. For a more complex system, the ModelList
may be part of a larger PropertyModel
that the mediator maintains.
class SimpleMenuMediator { private ModelList mModelList; SimpleMenuMediator(Context context, ModelList modelList) { mModelList = modelList; PropertyModel itemModel = generateListItem( ApiCompatibilityUtils.getDrawable(context.getResources(), R.drawable.icon), context.getResources().getString(R.string.label)); mModelList.add(new ModelListAdapter.ListItem(ListItemType.DEFAULT, itemModel)); } private PropertyModel generateListItem(Drawable icon, String text) { return new PropertyModel.Builder(SimpleMenuProperties.ALL_KEYS) .with(SimpleMenuProperties.ICON, icon) .with(SimpleMenuProperties.LABEL, text) .with(SimpleMenuProperties.CLICK_LISTENER, (view) -> handleClick(view)) .build(); } private void handleClick(View view) { // Do some click logic here. This would typically be done in the mediator. } }
These are the types of data that we want to apply to each list item in our menu.
class SimpleMenuProperties { @IntDef({ListItemType.DEFAULT}) @Retention(RetentionPolicy.SOURCE) /** * This can be one or more items depending on if the list is homogeneous. If homogeneous, * this definition can be skipped and 0 can be used in place of that parameter. */ public @interface ListItemType { int DEFAULT = 0; } /** The icon for the list item. */ public static final WritableObjectPropertyKey<Drawable> ICON = new WritableObjectPropertyKey<>(); /** The text shown next to the icon. */ public static final WritableObjectPropertyKey<String> LABEL = new WritableObjectPropertyKey<>(); /** The action that occurs when the list item is tapped. */ public static final WritableObjectPropertyKey<OnClickListener> CLICK_LISTENER = new WritableObjectPropertyKey<>(); public static final PropertyKey[] ALL_KEYS = {ICON, LABEL, CLICK_LISTENER}; }
As per the MVC architecture, this class is responsible for taking a model and applying that information in to to a provided view.
class SimpleMenuItemViewBinder { // This can optionally be in the coordinator file depending on the complexity. public static void bind(PropertyModel model, View view, PropertyKey propertyKey) { if (SimpleMenuProperties.ICON == propertyKey) { ((ImageView) view.findViewById(R.id.simple_menu_icon)).setImageDrawable( model.get(SimpleMenuProperties.ICON)); } else if (SimpleMenuProperties.LABEL == propertyKey) { ((TextView) view.findViewById(R.id.simple_menu_label)).setText( model.get(SimpleMenuProperties.LABEL)); } else if (SimpleMenuProperties.CLICK_LISTENER == propertyKey) { view.setOnClickListener(model.get(SimpleMenuProperties.CLICK_LISTENER)); } } }
<?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2019 The Chromium Authors Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="@color/modern_primary_color"> <org.chromium.ui.widget.ChromeImageView android:id="@+id/simple_menu_icon" android:layout_width="18dp" android:layout_height="18dp" android:layout_gravity="center_vertical" android:scaleType="centerInside"/> <TextView android:id="@+id/simple_menu_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center_vertical" android:textAppearance="@style/TextAppearance.BlackBody"/> </LinearLayout>