Skip to content

Instantly share code, notes, and snippets.

@mobiRic
Last active September 16, 2016 11:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mobiRic/655351e2e9c321ea86c00b2a685f337a to your computer and use it in GitHub Desktop.
Save mobiRic/655351e2e9c321ea86c00b2a685f337a to your computer and use it in GitHub Desktop.
Timeline Adapter
package mobi.glowworm.demo.timeline.dummy;
import android.support.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import mobi.glowworm.demo.timeline.TimelineItem;
/**
* Helper class for providing sample content for user interfaces created by
* Android template wizards.
* <p/>
* TODO: Replace all uses of this class before publishing your app.
*/
public class DummyContent {
/**
* An array of sample (dummy) items.
*/
public static final List<TimelineItem> ITEMS = new ArrayList<>();
/**
* A map of sample (dummy) items, by ID.
*/
public static final Map<String, DummyItem> ITEM_MAP = new HashMap<String, DummyItem>();
private static final int COUNT = 25;
static {
// Add some sample items.
for (int i = 1; i <= COUNT; i++) {
addItem(createDummyItem(i));
}
}
private static void addItem(DummyItem item) {
ITEMS.add(item);
ITEM_MAP.put(item.id, item);
}
private static DummyItem createDummyItem(int position) {
return new DummyItem(String.valueOf(position), "Item " + position, makeDetails(position));
}
private static String makeDetails(int position) {
return "Details about Item: " + position;
}
/**
* A dummy item representing a piece of content.
*/
public static class DummyItem implements TimelineItem {
public final String id;
public final String content;
public final String details;
public DummyItem(String id, String content, String details) {
this.id = id;
this.content = content;
this.details = details;
}
@Override
public String toString() {
return content;
}
@Override
public int getState() {
return TimelineItem.STATE_DEFAULT;
}
@Nullable
@Override
public CharSequence getTime() {
return String.valueOf(id);
}
@Nullable
@Override
public CharSequence getPrimaryText() {
return content;
}
@Nullable
@Override
public CharSequence getSecondaryText() {
return details;
}
@Override
public int getMarkerResId() {
return android.R.drawable.ic_menu_compass;
}
@Override
public int getTimelineResId() {
return android.R.drawable.ic_menu_compass;
}
}
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tvTLTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:text="10pm"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent">
<ImageView
android:id="@+id/ivTLTimeline"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/colorPrimary" />
<ImageView
android:id="@+id/ivTLMarker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/text_margin"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/tvTLPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Heading"
android:textAppearance="@style/TextAppearance.AppCompat.Body2" />
<TextView
android:id="@+id/tvTLSecondary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Description of something interesting"
android:textAppearance="@style/TextAppearance.AppCompat.Caption" />
</LinearLayout>
</LinearLayout>
package mobi.glowworm.demo.timeline;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.View;
import mobi.glowworm.demo.timeline.dummy.DummyContent;
public class ItemListActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_list);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setTitle(getTitle());
View recyclerView = findViewById(R.id.item_list);
assert recyclerView != null;
setupRecyclerView((RecyclerView) recyclerView);
}
private void setupRecyclerView(@NonNull RecyclerView recyclerView) {
recyclerView.setAdapter(new TimelineAdapter(DummyContent.ITEMS));
}
}
/*
* Copyright (C) 2016 Glowworm Software
*
* 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 mobi.glowworm.demo.timeline;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* A simple {@link RecyclerView.Adapter} implementation for displaying {@link TimelineItem} rows.
*/
public class TimelineAdapter
extends RecyclerView.Adapter<TimelineAdapter.ViewHolder> {
/**
* Implement this to provide a layout resource that can be displayed on the timeline.
* <p/>
* This layout should contain fields with the following predefined resource identifiers:
* <ul>
* <li>{@link R.id#tvTLTime}</li>
* <li>{@link R.id#tvTLPrimary}</li>
* <li>{@link R.id#tvTLSecondary}</li>
* <li>{@link R.id#ivTLMarker}</li>
* <li>{@link R.id#ivTLTimeline}</li>
* </ul>
*
* @param viewType The view type of the new View.
* @return a layout resource that holds a View of the given view type.
*/
@LayoutRes
protected int getViewHolderResId(int viewType) {
return R.layout.item_list_timeline_default;
}
@NonNull
private final List<TimelineItem> items;
public TimelineAdapter(@NonNull List<TimelineItem> items) {
this.items = items;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(getViewHolderResId(viewType), parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
holder.item = items.get(position);
if (holder.tvTime != null) {
holder.tvTime.setText(items.get(position).getTime());
}
if (holder.tvPrimary != null) {
holder.tvPrimary.setText(items.get(position).getPrimaryText());
}
if (holder.tvSecondary != null) {
holder.tvSecondary.setText(items.get(position).getSecondaryText());
}
if (holder.ivMarker != null) {
holder.ivMarker.setImageResource(items.get(position).getMarkerResId());
}
if (holder.ivTimeline != null) {
holder.ivTimeline.setImageResource(items.get(position).getTimelineResId());
}
}
@Override
public int getItemCount() {
return items.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public final View vRoot;
public final TextView tvTime;
public final TextView tvPrimary;
public final TextView tvSecondary;
public final ImageView ivMarker;
public final ImageView ivTimeline;
public TimelineItem item;
public ViewHolder(View view) {
super(view);
vRoot = view;
tvTime = (TextView) view.findViewById(R.id.tvTLTime);
tvPrimary = (TextView) view.findViewById(R.id.tvTLPrimary);
tvSecondary = (TextView) view.findViewById(R.id.tvTLSecondary);
ivMarker = (ImageView) view.findViewById(R.id.ivTLMarker);
ivTimeline = (ImageView) view.findViewById(R.id.ivTLTimeline);
}
@Override
public String toString() {
if ((item == null) || (item.getSecondaryText() == null)) {
return null;
}
return item.getSecondaryText().toString();
}
}
}
/*
* Copyright (C) 2016 Glowworm Software
*
* 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 mobi.glowworm.demo.timeline;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
/**
* Abstracted interface to represent basic information that can be displayed by items on a timeline.
* <p/>
* Items to be shown in the {@link TimelineAdapter} implement this interface.
*/
public interface TimelineItem {
/**
* Default state that can be returned by {@link #getState()}.
*/
int STATE_DEFAULT = 0;
/**
* Timelines often show items in different colours or icons based on some intrinsic state.
*
* @return integer value to determine what state this item is in
*/
int getState();
/**
* Timelines often display a date or time value on the left.
*
* @return text to display in the date/time/distance field; or null to hide the field
*/
@Nullable
CharSequence getTime();
/**
* Timelines often display 2 lines of text. This method returns the main "header" or
* "title" text to display.
*
* @return text to display as the header for the row; or null to hide the field
*/
@Nullable
CharSequence getPrimaryText();
/**
* Timelines often display 2 lines of text. This method returns the secondary "description"
* to display.
*
* @return text to display as the description for the row; or null to hide the field
*/
@Nullable
CharSequence getSecondaryText();
/**
* Timelines often display an icon for each row.
*
* @return resource ID of a drawable to display as the marker for this row; or zero to
* hide the field
*/
@DrawableRes
int getMarkerResId();
/**
* Timelines often display a vertical line linking the items. Sometimes this is a single
* line, all the same colour, and sometimes it can be broken in places, or take on different
* colours depending on the value of the {@link #getState()} method.
*
* @return resource ID of a drawable to display as the section of the timeline contained
* in this row; or zero to hide the timeline for this row
*/
@DrawableRes
int getTimelineResId();
}
@mobiRic
Copy link
Author

mobiRic commented Sep 16, 2016

Clean-room implementation of a Timeline adapter that uses an abstracted interface that can be reused across multiple "timeline" style lists.

Initial version is taken from the Android Master-Detail new project.

@mobiRic
Copy link
Author

mobiRic commented Sep 16, 2016

Abstracted out a Timeline interface to represent items in the list. Actual data objects implement this interface.

The adapter uses the interface methods to display information on each row.

Current version requires a given layout file, with predefined field IDs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment