Skip to content

Instantly share code, notes, and snippets.

@cbeyls
Last active May 11, 2020 08:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cbeyls/62984fc7dec2a600d722 to your computer and use it in GitHub Desktop.
Save cbeyls/62984fc7dec2a600d722 to your computer and use it in GitHub Desktop.
Vertical LinearLayout populated by a special adapter. Can be used as a lightweight ListView.
package be.digitalia.common.widgets;
import android.content.Context;
import android.database.DataSetObservable;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
/**
* Vertical LinearLayout populated by a special adapter.
*
* @author Christophe Beyls
*/
public class AdapterLinearLayout extends LinearLayout {
/**
* Implement this Adapter to populate the layout.
* Call notifyDataSetChanged() to update it.
*/
public static abstract class Adapter {
final DataSetObservable mDataSetObservable = new DataSetObservable();
public void notifyDataSetChanged() {
mDataSetObservable.notifyChanged();
}
public abstract int getCount();
public abstract View getView(int position, View convertView, ViewGroup parent);
}
class AdapterLinearLayoutDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
populateFromAdapter();
}
}
private Adapter mAdapter;
private AdapterLinearLayoutDataSetObserver mDataSetObserver;
public AdapterLinearLayout(Context context) {
this(context, null);
}
public AdapterLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(VERTICAL);
}
public void setAdapter(Adapter adapter) {
if (mAdapter == adapter) {
return;
}
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.mDataSetObservable.unregisterObserver(mDataSetObserver);
}
removeAllViews();
mAdapter = adapter;
if (adapter != null && mDataSetObserver != null) {
populateFromAdapter();
adapter.mDataSetObservable.registerObserver(mDataSetObserver);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mDataSetObserver = new AdapterLinearLayoutDataSetObserver();
if (mAdapter != null) {
populateFromAdapter();
mAdapter.mDataSetObservable.registerObserver(mDataSetObserver);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mAdapter != null) {
mAdapter.mDataSetObservable.unregisterObserver(mDataSetObserver);
}
mDataSetObserver = null;
}
void populateFromAdapter() {
final Adapter adapter = mAdapter;
final int currentCount = getChildCount();
final int newCount = adapter.getCount();
final int commonCount = Math.min(currentCount, newCount);
// 1. Update common views
for (int i = 0; i < commonCount; ++i) {
final View currentView = getChildAt(i);
final View newView = adapter.getView(i, currentView, this);
if (currentView != newView) {
// Edge case: View is not recycled
removeViewAt(i);
addView(newView, i);
}
}
// 2a. Add missing views
for (int i = commonCount; i < newCount; ++i) {
addView(adapter.getView(i, null, this));
}
// 2b. Remove extra views (starting from the end to avoid array copies)
for (int i = currentCount - 1; i >= commonCount; --i) {
removeViewAt(i);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment