Last active
May 11, 2020 08:57
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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