CheckBox in ListView, setVisibility using SimpleCursorAdapter and CursorLoader - android

Please, help me to find a solution how to set my checkboxes visible when I click on menu item "delete" and set invisible when I press "confirm" or "cancel".
I use SimpleCursorAdapter, cuz listview is filled from database with cursor loader...
here is my code:
MainActivity
public class MainActivity extends ActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor>{
final String LOG = "phonebookLogs";
private static final int LOADER_ID = 1;
Intent intentAddContact;
ListView lvMain;
CheckBox cbxList;
MenuItem addContact, deleteContact, settings, expimp, confirmDelete, cancelDelete;
DB mDB;
SimpleCursorAdapter scAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//find ListView
lvMain = (ListView)findViewById(R.id.lvMain);
//calling for creating adapter
onCreateAdapter();
}
public void onCreateAdapter(){
String[] from = new String[] { DB.COL_LINK, DB.COL_SURNAME, DB.COL_NAME };
int[] to = new int[] { R.id.ivPhoto, R.id.tvSurname, R.id.tvName, };
if(to[0] == 0){
to[0] = R.drawable.default_contact;
}
scAdapter = new SimpleCursorAdapter(this, R.layout.item, null, from, to, 0);
lvMain.setAdapter(scAdapter);
// loader for reading data
getSupportLoaderManager().initLoader(LOADER_ID, null, this);
}
public void deleteRecord(){
//when MenuItem "Delete" is clicked
addContact.setVisible(false);
deleteContact.setVisible(false);
settings.setVisible(false);
expimp.setVisible(false);
confirmDelete.setVisible(true);
cancelDelete.setVisible(true);
}
public void onCancelDeleteRecord(){
////when MenuItem "cancel" is clicked
addContact.setVisible(true);
deleteContact.setVisible(true);
settings.setVisible(true);
expimp.setVisible(true);
confirmDelete.setVisible(false);
cancelDelete.setVisible(false);
}
public void confirmDeleteRecord(){
////when MenuItem "confirm" is clicked
addContact.setVisible(true);
deleteContact.setVisible(true);
settings.setVisible(true);
expimp.setVisible(true);
confirmDelete.setVisible(false);
cancelDelete.setVisible(false);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu)
{
//find all MenuItems
addContact = menu.findItem(R.id.addContact);
deleteContact = menu.findItem(R.id.deleteContact);
settings = menu.findItem(R.id.settings);
expimp = menu.findItem(R.id.expimp);
confirmDelete = menu.findItem(R.id.confirmDelete);
cancelDelete = menu.findItem(R.id.cancelDelete);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item){
switch(item.getItemId()){
case R.id.addContact:
intentAddContact = new Intent(this, NewContact.class);
startActivity(intentAddContact);
break;
case R.id.deleteContact:
deleteRecord();
break;
case R.id.settings:
break;
case R.id.expimp:
break;
case R.id.confirmDelete:
confirmDeleteRecord();
break;
case R.id.cancelDelete:
onCancelDeleteRecord();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle bndl) {
return new MyCursorLoader(this, mDB);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
scAdapter.swapCursor(cursor);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
scAdapter.swapCursor(null);
}
}
DB.class and CursorLoader.class are fine, simple query and loading.
and my XML-file for ListView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin"
android:layout_weight="0.5"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/margin"
android:orientation="vertical" >
<ImageView
android:id="#+id/ivPhoto"
android:layout_width="#dimen/imageWidth"
android:layout_height="#dimen/imageHeight"
android:layout_gravity="center_vertical"
android:contentDescription="#string/photoDescription"
android:src="#drawable/default_contact" />
</LinearLayout>
<TextView
android:id="#+id/tvName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="#dimen/margin"
android:text=""
android:textSize="#dimen/textSize" />
<TextView
android:id="#+id/tvSurname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="#dimen/margin"
android:text=""
android:textSize="#dimen/textSize" />
</LinearLayout>
<CheckBox
android:id="#+id/cbxList"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="#dimen/margin"
android:layout_weight="0.2"
android:visibility="invisible" />
</LinearLayout>
I have read a lot already, but how to realize it without creating my own adapter still can't get...
will be thanksfull to any help in finding solution!

You can set your checkbox as visible with: cbxlist.setVisibility(View.VISIBLE);
And if you want it completely gone, use (ie make it look as if it was never added): cbxlist.setVisibility(View.GONE);
If you want it to be just invisible, but still occupy the same space: cbxlist.setVisibility(View.INVISIBLE);
Edit:
for(int i = 0; i < lvMain.getChildCount(); i++) {
lvMain.getChildAt(i).findViewById(R.id.cbxList).setVisibility(View.VISIBLE);
}
That should set all of your checkbox's to visible. Similarly call for View.INVISIBLE when required.

If you want to change visibility of each checkbox in your listview (assuming your XML is your list row view), you need to create your custom adapter and override getView method.
In there, you will do the following:
#Override
public View getView(final int position, final View convertView, final ViewGroup parent) {
cBox = (CheckBox ) convertView.findViewById(R.id.cbxList);
cBox.setVisibility(View.GONE);
return convertView;
}

Related

setOnItemClickListener of ListView doesn't work

I have a rather strange situation. I display in a listview some products with their details that are read from an SQLite database via a Content provider. However, when I click in any row of the list view nothing happens. So I am posting some of my code.
MainActivity
public class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>{
private static final String TAG = MainActivity.class.getSimpleName();
private static final int PRODUCT_LOADER = 0;
ProductCursorAdapter mCursorAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
showAddProductDialog();
}
});
ListView productListView = (ListView) findViewById(R.id.list_view_product);
View emptyView = findViewById(R.id.empty_view);
productListView.setEmptyView(emptyView);
mCursorAdapter = new ProductCursorAdapter(this, null);
productListView.setAdapter(mCursorAdapter);
productListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
Intent i = new Intent(MainActivity.this,EditActivity.class);
Uri currentProductUri = ContentUris.withAppendedId(ProductEntry.CONTENT_URI,id);
i.setData(currentProductUri);
startActivity(i);
}
});
getLoaderManager().initLoader(PRODUCT_LOADER, null, this);
}
private void showAddProductDialog() {
AddDialogFragment newFragment = new AddDialogFragment();
newFragment.show(getSupportFragmentManager(), getString(R.string.add_product));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
String[] projection = {
ProductEntry._ID,
ProductEntry.COLUMN_PRODUCT_NAME,
ProductEntry.COLUMN_PRODUCT_QUANTITY,
ProductEntry.COLUMN_PRODUCT_PRICE,
ProductEntry.COLUMN_PRODUCT_IMAGE};
return new CursorLoader(this,
ProductContract.ProductEntry.CONTENT_URI,
projection,
null,
null,
null
);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
mCursorAdapter.swapCursor(data);
}
#Override
public void onLoaderReset(Loader<Cursor> loader) {
mCursorAdapter.swapCursor(null);
}
}
and activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_margin"
android:paddingLeft="#dimen/activity_margin"
android:paddingRight="#dimen/activity_margin"
android:paddingTop="#dimen/activity_margin"
tools:context="com.example.android.invetoryapp.MainActivity">
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#android:drawable/ic_input_add"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_margin="#dimen/fab_margin" />
<ListView
android:id="#+id/list_view_product"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/activity_margin"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:focusable="false"
android:focusableInTouchMode="false"/>
/>
<RelativeLayout
android:id="#+id/empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TextView
android:id="#+id/empty_title_text"
style="#style/EmptyTextView"
android:text="#string/empty_view_subtitle_text" />
</RelativeLayout>
As you can see I am using those attributes, as suggesting in different answers I found, but still nothing happens when I am clicking a row.
android:focusable="false"
android:focusableInTouchMode="false"
How can i fix that error?
Thanks,
Theo.
Try with add below lines in ListView attributes of your activity_main.xml like this:-
android:descendantFocusability="blocksDescendants"
android:focusable="true"
android:focusableInTouchMode="true"
Remove below lines from your ListView in xml;
android:focusable="false"
android:focusableInTouchMode="false"
Either remove these lines
android:focusable="false"
android:focusableInTouchMode="false"
or make them true
android:focusable="true"
android:focusableInTouchMode="true"
add this lines to listview:
android:focusable="true"
android:focusableInTouchMode="true"
add this lines to other view which has focusable feature:
android:focusable="false"
android:focusableInTouchMode="false"
Remove these line
android:focusable="false"
android:focusableInTouchMode="false"
And Add on Activity
listview.setOnClickListener

How to make the items in the listview respond to the click on that particular row on the listview

I am displaying a tab and which has two tags Category1 and Category2.
The list gets populated based on the data in the tables for category1 and category2. This works fine but to make the items in the listview respond in a certain way to clicks made on the listview is what I am stuck at. Like for example:
I am trying to make the checkbox become visible and checked when the user long clicks on the particular row in the listview. I am trying to code it but I have no idea where to begin. There aren't questions asked on this topic specifically. Below is the code that I have tried.
FragmentClass
public class CategoryFragment extends Fragment{
private ListView listView;
private String currentTabTag;
private CategoryAdapter1 categoryAdapter1;
private CategoryAdapter2 categoryAdapter2;
private MergeAdapter adapter = new MergeAdapter();
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// inflate the layout for this fragment
View view = inflater.inflate(R.layout.activity_category_fragment_list, container, false);
// get references to widgets
listView = (ListView) view.findViewById (R.id.ListView);
// get the current tab
TabHost tabHost = (TabHost) container.getParent().getParent();
currentTabTag = tabHost.getCurrentTabTag();
// refresh the category list view
refreshCategoryList();
listView.setOnItemLongClickListener(this);
// return the view
return view;
}
public void refreshCategoryList() {
// get category list for current tab from database
Context context = getActivity().getApplicationContext();
CategoryDatabase categoryDatabase = new CategoryDatabase(context);
if(currentTabTag.equals("Category 1")) {
ArrayList<Category1> category1ArrayList = categoryDatabase.getAllCategory1(currentTabTag);
// create adapter and set it in the ListView widget
categoryAdapter1 = new Category1Adapter(context, category1ArrayList);
adapter.add(Category1Adapter);
}
else if(currentTabTag.equals("Category 2"))
{
ArrayList<Category2> category2ArrayList = categoryDatabase.getAllCategory2(currentTabTag);
// create adapter and set it in the ListView widget
categoryAdapter2 = new categoryAdapter2(context, category2ArrayList);
adapter.add(categoryAdapter2);
}
listView.setAdapter(adapter);
}
#Override
public void onResume() {
super.onResume();
refreshTaskList();
}
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
ItemsListLayout itemsListLayout = new ItemsListLayout(context);
switch (view.getId()) {
case R.id.listView: {
itemsListLayout.setMyListItems();
Toast.makeText(context,"Why cant I be called?",Toast.LENGTH_SHORT).show();
//registerForContextMenu(view);
}
/*default:
Intent intent = new Intent(context, MyCategoryAddEdit.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intent.putExtra("categoryId", category.getId());
intent.putExtra("editMode", true);
context.startActivity(intent);
break;*/
}
return false;
}
}
activity_category_fragment_list
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<ListView
android:id="#+id/prescriptorsListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:longClickable="true"
android:descendantFocusability="blocksDescendants">
</ListView>
</LinearLayout>
ItemsListLayout
public class ItemsListLayout extends RelativeLayout implements View.OnCreateContextMenuListener {
private CheckBox completedCheckBox;
private TextView nameTextView;
private TextView notesTextView;
private ListView listView;
private CategoryDatabase categoryDatabase;
private Context context;
public ItemsListLayout(Context context) { // used by Android tools
super(context);
}
public ItemsListLayout(Context context, Prescription p) {
super(context);
// set context and get db object
this.context = context;
categoryDatabase = new CategoryDatabase(context);
// inflate the layout
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.activity_my_category_items_list_layout, this, true);
// get references to widgets
completedCheckBox = (CheckBox) findViewById(R.id.completedCheckBox);
completedCheckBox.setVisibility(GONE);
nameTextView = (TextView) findViewById(R.id.nameTextView);
notesTextView = (TextView) findViewById(R.id.notesTextView);
//listView = (ListView) findViewById(R.id.listView);
// set listeners
//listView.setOnItemLongClickListener(this);
// set task data on widgets
setCategory1(p);
}
public void setCategory1(setCategory1 p) {
setCategory1 = p;
nameTextView.setText(setCategory1.getCategory1Name());
// Remove the notes if empty
if (setCategory1.getMedicineName().equalsIgnoreCase("")) {
notesTextView.setVisibility(GONE);
}
else {
notesTextView.setText(setCategory1.getDescriptionName());
}
}
/*#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
switch (view.getId()) {
case R.id.prescriptorsListView:
completedCheckBox.setVisibility(VISIBLE);
completedCheckBox.setChecked(true);
break;
default:
Intent intent = new Intent(context, MyCategoryAddEdit.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intent.putExtra("categoryId", category.getId());
intent.putExtra("editMode", true);
context.startActivity(intent);
break;
}
return false;
}
*/
public void setMyListItems()
{
completedCheckBox = (CheckBox) findViewById(R.id.completedCheckBox);
completedCheckBox.setVisibility(VISIBLE);
completedCheckBox.setChecked(true);
}
#Override
public void onCreateContextMenu(ContextMenu contextMenu, View view, ContextMenu.ContextMenuInfo contextMenuInfo)
{
super.onCreateContextMenu(contextMenu);
//MenuInflater inflater = this.context.
}
}
activity_my_category_items_list_layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relativeLayoutTaskItem"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clickable="false"
android:descendantFocusability="blocksDescendants"
android:focusable="false"
android:focusableInTouchMode="false">
<CheckBox
android:id="#+id/completedCheckBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_margin="5dp"
android:button="#drawable/btn_check"
android:textColor="#ffffff"
android:longClickable="true"
android:focusable="false"
android:clickable="false"
android:focusableInTouchMode="false"/>
<TextView
android:id="#+id/nameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="#+id/completedCheckBox"
android:layout_alignBottom="#+id/completedCheckBox"
android:layout_toRightOf="#+id/completedCheckBox"
android:text=""
android:textColor="#android:color/white"
android:textSize="20dp"
android:textStyle="bold"
android:longClickable="true"
android:focusable="false"
android:clickable="false"
android:textIsSelectable="false"
android:focusableInTouchMode="false"/>
<TextView
android:id="#+id/notesTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/nameTextView"
android:layout_marginTop="-5dp"
android:layout_toRightOf="#+id/completedCheckBox"
android:paddingBottom="7dp"
android:textColor="#android:color/white"
android:textSize="18dp"
android:longClickable="true"
android:focusable="false"
android:clickable="false"
android:textIsSelectable="false"
android:focusableInTouchMode="false"/>
</RelativeLayout>
Any kind of help is appreciated. Especially code snippets if possible :).
I suggest you to read this blog, it has step by step procedure of what exactly you want to achieve. You can even clone the project from github.

Android ListView shows Old and New values using BaseAdapter

I am using a custom BaseAdapter implementation for a Listview. Everything is fine until there are many items in the listview and the scrolling mechanism appears. (items exceed the listview height). When I now delete one item the listview refreshes and shows the right data for just milliseconds. After that it shows also the old values from time before deletion. But only for the items after the deleted entry. Every item above is ok.
When I start scrolling now, everything is fine again?! Looks somehow as there is some caching problem or whatever?!
See the following files and pictures.
CustomBaseAdapter:
public class CustomBaseAdapter extends BaseAdapter {
private Activity context;
private List<Entry> objects;
private LayoutInflater layoutInflater = null;
private int textViewResourceId;
public CustomBaseAdapter(Activity context, int textViewResourceId,
List<Entry> objects) {
this.textViewResourceId = textViewResourceId;
this.objects = objects;
this.context = context;
layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public void updateEntries(List<Entry> entries){
ThreadPreconditions.checkOnMainThread();
List<Entry> entryHelper = new ArrayList<>();
entryHelper.addAll(entries);
this.objects.clear();
this.objects.addAll(entryHelper);
}
#Override
public int getCount() {
return objects.size();
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
EntryDataHolder holder;
//TODO Views recycling implementieren. Ist derzeit auskommentiert aufgrund des Bug #203
// If null we create row, if not we get the holder object of current row
if (convertView == null) {
// set the layout
LayoutInflater li = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = li.inflate(textViewResourceId, null);
holder = new EntryDataHolder(row);
row.setTag(holder);
} else {
holder = (EntryDataHolder) row.getTag();
}
// fill components with value
Entry entry = objects.get(position);
holder.tvCol1.setText(entry.getDateAsStringWithoutYear());
holder.tvCol2.setText(entry.getDescription());
holder.tvCol3.setText(entry.getAmountAsStringWithCurrency());
// highlight text if item can be associated with a deposit
if(entry instanceof Expense){
if(((Expense)entry).getAssociatedDeposit() != null){
ComponentUtil.setDepositAssociationColoring(holder.tvCol1);
ComponentUtil.setDepositAssociationColoring(holder.tvCol2);
ComponentUtil.setDepositAssociationColoring(holder.tvCol3);
}else{
ComponentUtil.setStandardColoring(holder.tvCol1);
ComponentUtil.setStandardColoring(holder.tvCol2);
ComponentUtil.setStandardColoring(holder.tvCol3);
}
}
row.setTag(holder);
return row;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public Entry getItem(int position) {
return objects.get(position);
}
class EntryDataHolder {
public TextView tvCol1;
public TextView tvCol2;
public TextView tvCol3;
public EntryDataHolder(View base){
tvCol1 = (TextView) base.findViewById(R.id.tvCol1);
tvCol2 = (TextView) base.findViewById(R.id.tvCol2);
tvCol3 = (TextView) base.findViewById(R.id.tvCol3);
}
}
}
Activity class:
public class RevenueListActivity extends BaseActivity implements
IDialogActionListener {
// view component references
private TextView tvHeader;
private TextView tvTotal;
private ListView lvData;
private CustomBaseAdapter adapter;
private List<Entry> tmpRevenues;
private AdView adView;
private MonthControl mControl;
private AbstractDialog entryDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_entry_list);
// Add AdView
LinearLayout layout = (LinearLayout) findViewById(R.id.llAdView);
adView = AdViewManager.addAdToView(this, layout);
initializeComponents();
registerForContextMenu(lvData);
loadIntentVariables();
loadEntryList();
}
/**
* Create the options menu for this activity
*/
#Override
public boolean onCreateOptionsMenu(android.view.Menu menu) {
MenuInflater menuInflator = getMenuInflater();
menuInflator.inflate(R.menu.activity_entry_list, menu);
// Readonly configuration
MenuItem miAddEntry = menu.findItem(R.id.miAddEntry);
if (mControl.getIsSaveable()) {
miAddEntry.setVisible(true);
} else {
miAddEntry.setVisible(false);
}
return true;
}
/**
* Create the context menu for the list
*/
#Override
public void onCreateContextMenu(android.view.ContextMenu menu, View v,
android.view.ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
// Readonly configuration
if (mControl.getIsSaveable()) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.activity_entry_context_menu, menu);
}
}
/**
* Called if one of the Context Menu Item was clicked
*/
#Override
public boolean onContextItemSelected(MenuItem item) {
// get selected item from list view
AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
.getMenuInfo();
Object selectedObject = lvData.getAdapter().getItem(info.position);
Entry selectedEntry = (Entry) selectedObject;
switch (item.getItemId()) {
case R.id.miDeleteEntry:
deleteSelectedEntry(selectedEntry);
break;
case R.id.miEditEntry:
editSelectedEntry(selectedEntry);
break;
default:
return super.onContextItemSelected(item);
}
return true;
}
/**
* Deletes the current selected entry from month control
*/
private void deleteSelectedEntry(Entry entryToDelete) {
//mControl.deleteRevenue(entryToDelete);
tmpRevenues.remove(entryToDelete);
adapter.updateEntries(tmpRevenues);
adapter.notifyDataSetChanged();
}
/**
* Opens the dialog for editing the selected entry
*
* #param entryToEdit
*/
private void editSelectedEntry(Entry entryToEdit) {
entryDialog.showDialog(entryToEdit);
}
/**
* Called if one of the Option Menu Item was clicked
*/
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// check which option menu item was clicked
switch (item.getItemId()) {
case R.id.miAddEntry:
entryDialog.showDialog(null);
break;
default:
return super.onOptionsItemSelected(item);
}
return true;
}
/**
* Called when dialog was committed with ok
*
* #param event
*/
public void dialog_commitHandler(DialogEvent event) {
// check which type of action was performed with the dialog
if (event.getEventType().equals(DialogEvent.EDIT_ENTRY_EVENT)) {
// Notify Month Control observers that the object has been modified.
//mControl.changeOccured();
} else if (event.getEventType().equals(DialogEvent.NEW_ENTRY_EVENT)) {
//mControl.addRevenue(event.getEntry());
tmpRevenues.add(event.getEntry());
}
adapter.updateEntries(tmpRevenues);
adapter.notifyDataSetChanged();
}
/**
* Called when the dialog was canceled
*/
public void dialog_cancelHandler() {
// Do nothing
}
/**
* inject all needed components
*/
private void initializeComponents() {
tvHeader = (TextView) findViewById(R.id.tvEntryListHeader);
tvTotal = (TextView) findViewById(R.id.tvTotal);
lvData = (ListView) findViewById(R.id.lvData);
}
/**
* injects the right dialog after intent variables were loaded
*/
private void initializeDialog() {
entryDialog = new RevenueDialog(this, R.layout.dialog_revenue);
entryDialog.addEventListener(this);
}
/**
* Loads extra values from intent and configures activity
*/
private void loadIntentVariables() {
mControl = MonthControl.getInstance(null);
// Readonly configuration
tvHeader.setText(getText(R.string.tv_revenue_header)
+ (mControl.getIsSaveable() ? "" : " ("
+ getString(R.string.tv_archived_month) + ")"));
// after intent were loaded we can init the associated dialog
initializeDialog();
}
/**
* Iterates through the entry list and adds them to a Adapter, which will be
* used for the list view
*/
private void loadEntryList() {
tmpRevenues = new ArrayList<Entry>();
tmpRevenues.addAll(mControl.getRevenues());
adapter = new CustomBaseAdapter(this,
R.layout.list_item_layout_revenue, tmpRevenues);
lvData.setAdapter(adapter);
// make calculations
calculateSum();
}
/**
* calculates the sum of all entries
*/
private void calculateSum() {
BigDecimal sum = BigDecimalFactory.createBigDecimal("0");
for (Entry entry : tmpRevenues) {
sum = sum.add(entry.getAmount());
}
tvTotal.setText(sum.toString() + " €");
}
#Override
protected void onPause() {
if (adView != null)
adView.resume();
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
if (adView != null)
adView.resume();
}
#Override
protected void onDestroy() {
if (adView != null)
adView.destroy();
super.onDestroy();
}
}
Model class code:
public void deleteRevenue(Entry entry) {
LogUtil.debug(MonthControl.class, TAG, "Deleting revenue...");
revenues.remove(entry);
notifyListener();
}
public List<Entry> getRevenues() {
if (revenues == null) {
revenues = new ArrayList<Entry>();
}
return revenues;
}
The list item Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="40dp"
android:minHeight="40dp"
android:orientation="horizontal"
android:weightSum="1.0" >
<TextView
android:id="#+id/tvCol1"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.3"
android:ellipsize="marquee"
android:lines="1"
android:scrollHorizontally="true"
android:singleLine="true" />
<TextView
android:id="#+id/tvCol2"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.5"
android:ellipsize="marquee"
android:lines="1"
android:scrollHorizontally="true"
android:singleLine="true" />
<TextView
android:id="#+id/tvCol3"
android:layout_width="0px"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.2"
android:ellipsize="marquee"
android:lines="1"
android:scrollHorizontally="true"
android:singleLine="true" />
</LinearLayout>
Befor deletion:
After deletion of 5th item:
After scrolling:
UPDATE: Solution
It is the layout. I just removed one liner_layout layer the listview was contained in. Now everything ist fine.
This is the tested working layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/llAdView"
android:layout_width="fill_parent"
android:layout_height="75px"
android:orientation="vertical">
<!-- AdView inserted here at runtime -->
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="40dp"
android:background="#color/blue"
android:orientation="vertical" >
<TextView
android:id="#+id/tvEntryListHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|center_horizontal|center_vertical"
android:textSize="18dip"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginTop="10dip"
android:weightSum="1.0" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.3"
android:text="#string/tv_date_header" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.5"
android:text="#string/tv_description_header" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.2"
android:text="#string/tv_amount_header" />
</LinearLayout>
<ListView
android:id="#+id/lvData"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="8dp"
android:background="#drawable/border_ui"
android:divider="#color/dark_grey"
android:dividerHeight="1dp"
android:padding="4dp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="40dp"
android:layout_marginTop="8dp"
android:weightSum="1.0" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.8"
android:text="#string/tv_total" />
<TextView
android:id="#+id/tvTotal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.2" />
</LinearLayout>
</LinearLayout>
Your problem seems to be from
adapter.updateEntries(mControl.getRevenues());
It seems like mControl.getRevenues() returns the previous data.
Try commenting this line out and see.
BTW, you don't need to call adapter.updateEntries because notifyDataSetChange will do the adapter update.
You are missing which is a must,
row.setTag(holder);// this is missing.
return row;
in your getView Method
and also, this is somewhat wrong according to your approach, So change to this and see,
public void updateEntries(List<Entry> entries){
ThreadPreconditions.checkOnMainThread();
this.objects.clear();
this.objects.addAll(entries);
}
and also make sure that,
mControl.getRevenues() only returns values that are not deleted, if this method tend to return the same data as old data, then this is also wrong.
I think I got where the problem is,
remove the following method from your adapter.
public void updateEntries(List<Entry> entries){
ThreadPreconditions.checkOnMainThread();
List<Entry> entryHelper = new ArrayList<>();
entryHelper.addAll(entries);
this.objects.clear();
this.objects.addAll(entryHelper);
}
This is what causing the problem.
and in this method,,
/**
* Deletes the current selected entry from month control
*/
private void deleteSelectedEntry(Entry entryToDelete) {
//mControl.deleteRevenue(entryToDelete);
tmpRevenues.remove(entryToDelete);
adapter.notifyDataSetChanged();
}
adapter.updateEntries(tmpRevenues); you will not call this method because when you remove the Entry earler, you are actually removing the items inside the adapter, because you are passing the same reference to the adapter.
But still, debug the application and see when you do the remove on the tmpRevenues that Entry is actually getting removed.
I am quoting your comment,
if i update the "updateEntries" function as you showed i end up in
that scenario that my list is completely empty after deleting one
item. ?!? Maybe because of the refernce to the original list.
This solution will fix the above issue

highlighting selected item in custom list view using context menu?

I've been trying to set my background colour on this list view and with following multiple tutorials it just doesn't come up, yet no errors are shown.
What I've got is an xml file called colours in the values folder:
<resources>
<drawable name="red_colour">#6D0E0E</drawable>
</resources>
Which links to an xml in the drawable folder:
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_pressed="true"
android:state_activated="true"
android:drawable="#drawable/red_colour">
</item>
</selector>
I've tried placing the following code android:background:#id"colourhighlight.xml"
literally everywhere based on various tutorials yet no luck?
Any advice? Please help...
I've got one main class with a context menu:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_contacts);
// The contacts from the contacts content provider is stored in this cursor
mMatrixCursor = new MatrixCursor(new String[] { "_id","name","photo","details"} );
// Adapter to set data in the listview
mAdapter = new SimpleCursorAdapter(getBaseContext(),
R.layout.lv_layout,
null,
new String[] { "name","photo","details"},
new int[] { R.id.tv_name,R.id.iv_photo,R.id.tv_details}, 0);
// Getting reference to listview
final ListView lstContacts = (ListView) findViewById(R.id.lst_contacts);
// Setting the adapter to listview
lstContacts.setAdapter(mAdapter);
// Creating an AsyncTask object to retrieve and load listview with contacts
ListViewContactsLoader listViewContactsLoader = new ListViewContactsLoader();
// Starting the AsyncTask process to retrieve and load listview with contacts
listViewContactsLoader.execute();
//Selecting and highlighting the elements in the listview
lstContacts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
view.setActivated(true);
}
});
//Creating the context menu and the options for it
listview = (ListView) findViewById(R.id.lst_contacts);
listview.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
listview.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) {
count = count+1;
mode.setTitle(count + " Contacts Selected");
}
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
MenuInflater inflater = mode.getMenuInflater();
inflater.inflate(R.menu.contact_context_menu, menu);
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch(item.getItemId()){
case R.id.delete_id:
Toast.makeText(getBaseContext(), count + " Contacts Deselected", Toast.LENGTH_SHORT).show();
count = 0;
mode.finish();
return true;
//break;
default:
return false; //break;
}
//return false;
}
#Override
public void onDestroyActionMode(ActionMode mode) {
}
});
}
lv_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/iv_photo"
android:maxHeight="80dp"
android:maxWidth="80dp"
android:adjustViewBounds="true"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:id="#+id/tv_name"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/iv_photo"
android:layout_toEndOf="#+id/iv_photo" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:id="#+id/tv_details"
android:layout_below="#+id/tv_name"
android:layout_toRightOf="#+id/iv_photo"
android:layout_toEndOf="#+id/iv_photo" />
</RelativeLayout>
Main layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context="com.example.ankhit.saveme.UserContacts"
android:background="#drawable/colourhighlight"
>
<ListView
android:id="#+id/lst_contacts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/button"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/instructions"
android:id="#+id/button"
android:onClick="showInstructions"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
#Override
public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked)
{
try
{
final int checkedCount = listView.getCheckedItemCount();
mode.setTitle(""+checkedCount);
if (checked)
{
adapter.setNewSelection(position, checked);
}
else
{
adapter.removeSelection(position);
}
adapter.notifyDataSetChanged();
}
catch (Exception e)
{
e.printStackTrace();
}
}
add these methods in your adapter class
private HashMap<Integer, Boolean> mSelection = new HashMap<Integer, Boolean>();
public void setNewSelection(int position, boolean value)
{
mSelection.put(position, value);
}
public boolean isPositionChecked(int position)
{
Boolean result = mSelection.get(position);
return result == null ? false : result;
}
public Set<Integer> getCurrentCheckedPosition() {
return mSelection.keySet();
}
public void removeSelection(int position) {
mSelection.remove(position);
}
public void clearSelection() {
mSelection = new HashMap<Integer, Boolean>();
}
call this method inside getView() method of adapter it works properly
convertView.setBackgroundColor(mContext.getResources().getColor(android.R.color.transparent));
if (mSelection.get(position) != null)
{
convertView.setBackgroundColor(mContext.getResources().getColor(R.color.message_selector_holo_blue));
}
If you want highlighting selected row completely then change the background color of the convertview
lstContacts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
view.setBackgroundColor(mContext.getResources().getColor(android.R.color.transparent));
}
});

press button in each list in ListActivity

I want to make application that when press the button it will make each sound and each button contain in list (like this pic : enter link description here) so I wrote Im_SensShow.java which extends ListActivity and have imsen_main.xml and imsen_row.xml and it doesn't work(force close) please help
package com.android.proj; public class Im_SensShow extends ListActivity {
/** Called when the activity is first created. */
private DBAdapter db ;
private Cursor cursor ;
private static final int INSERT_ID = Menu.FIRST;
private static final int CHANGE_ID = Menu.FIRST + 1;
private static final int EDIT_ID = Menu.FIRST + 2;
private static final int DELETE_ID = Menu.FIRST + 3;
//this will store situation id that is sent from main
private long thim_sens_id;
private ImageButton menuCarBtn;
TextView MyOutputText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.imsen_main);
MyOutputText = (TextView)findViewById(R.id.OutputText);
db = new DBAdapter(this);
setBinding();
//setOnEvent();
listData();
registerForContextMenu(getListView());
}
private void setBinding(){
//Binding Objects
menuCarBtn = (ImageButton)findViewById(R.id.menuCarBtn);
}
private void listData(){
db.open();
Bundle dataBundle = Im_SensShow.this.getIntent().getExtras();
thim_sens_id = dataBundle.getLong("THIMSENSID");
cursor = db.getIm_Sen_List(thim_sens_id,1);
MyOutputText.setText(thim_sens_id+"t");
startManagingCursor(cursor);
ListAdapter list = new SimpleCursorAdapter(
this,
R.layout.imsen_row,
cursor,
new String[] {DBAdapter.KEY_IM_SENS, DBAdapter.KEY_READING},
new int[] {R.id.im_sens, R.id.reading});
setListAdapter(list);
db.close();
menuCarBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(getBaseContext(), "hello", Toast.LENGTH_LONG).show() ;
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu){
super.onCreateOptionsMenu(menu);
menu.add(0, INSERT_ID,0, R.string.menu_insert);
menu.add(0, CHANGE_ID,0, R.string.menu_change_lan);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case INSERT_ID:
Cursor c = cursor;
Intent create_Im_Sens = new Intent(Im_SensShow.this,Im_SensShow.class);
Bundle dataBundle = new Bundle(0);
// we want to create record in sit 2 so send a sit 1 primary key is enough
dataBundle.putLong("THIMSENSID", thim_sens_id);
//send 0 since we will notify create activity that this is for create : data does not exist in sit 2 table yet
dataBundle.putLong("IMSENSID", 0);
create_Im_Sens.putExtras(dataBundle); //
startActivity(create_Im_Sens);
break;
case CHANGE_ID:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final CharSequence[] items = { "อังกฤษ", "ฝรั่งเศส", "เยอรมัน",
"อิตาลี", "สเปน", "แสดงทุกภาษา" };
builder.setTitle("เลือกภาษาที่แสดง");
builder.setItems(items, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
// Toast.makeText(getApplicationContext(), items[item],
// Toast.LENGTH_SHORT).show();
}
});
AlertDialog alert = builder.create();
alert.show();
break;
default:
break;
}
return true;
}
#Override
public void onCreateContextMenu(ContextMenu menu, View v,ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.setHeaderTitle("จัดการข้อมูล");
menu.add(0, EDIT_ID, 0, R.string.menu_edit);
menu.add(0, DELETE_ID, 0, R.string.menu_delete);
}
/*
#Override
public boolean onContextItemSelected(MenuItem item){
switch(item.getItemId()){
case EDIT_ID:{
Cursor c = cursor;
Intent edit_Th_Im_Sens = new Intent(Im_SensShow.this,Th_Im_SensEdit.class);
Bundle bundle = new Bundle();
bundle.putLong("SITUATION2ID", sit2_id);
bundle.putLong("THIMSENSID", c.getLong(c.getColumnIndexOrThrow(DBAdapter.KEY_TH_IM_SENS_ID)));
bundle.putString("THIMSENS",c.getString(c.getColumnIndexOrThrow(DBAdapter.KEY_TH_IM_SENS)));
edit_Th_Im_Sens.putExtras(bundle);
startActivityForResult(edit_Th_Im_Sens,1);
return true;
}
case DELETE_ID:{
db.open();
db.deleteRecord(DBAdapter.TH_IM_SENS_TABLE,DBAdapter.KEY_TH_IM_SENS_ID,cursor.getLong(cursor.getColumnIndexOrThrow(DBAdapter.KEY_TH_IM_SENS_ID)));
Toast.makeText(getBaseContext(), getString(R.string.save_data), Toast.LENGTH_LONG).show() ;
listData();
return true;
}
}
return super.onContextItemSelected(item);
}
/*
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Cursor c = cursor;
c.moveToPosition(position);
Intent showTh_Im_Sens = new Intent(Th_Im_SensShow.this,Th_Im_SensShow.class);
Bundle dataBundle = new Bundle(0);
dataBundle.putLong("SITUATIONID", 0);
showTh_Im_Sens.putExtras(dataBundle); //
startActivity(showTh_Im_Sens);
}
*/
#Override
public void onResume(){
super.onResume();
listData();
}
}
imsen_main.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:text="ค้นหา "
android:id="#+id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<AutoCompleteTextView
android:text=""
android:id="#+id/AutoCompleteTextView01"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</AutoCompleteTextView>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="#98CAF3">
<TextView
android:text="imsentences"
android:id="#+id/TextView03"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="27dip"
android:textColor="#FFFFFF"
android:textColorHighlight="#98CAF3">
</TextView>
<ListView
android:id="#android:id/list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:footerDividersEnabled="true"
android:cacheColorHint="#00000000"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView android:id="#+id/im_sens"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1."/>
imsen_row.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView android:id="#+id/lang"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1."
android:textSize="16dip" />
<TextView android:id="#+id/im_sens"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1."
android:textSize="24dip" />
<TextView android:id="#+id/reading"
android:layout_width="fill_parent"
android:textSize="24dip"
android:layout_height="wrap_content"
android:text="reading"
android:layout_weight="1."/>
<ImageButton
android:id="#+id/menuCarBtn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/car"
android:background="#null"
/>
You need a custom adapter for the list in which you have a holder for each list item which holds the items and allows them to be pressed and have listeners... etc.
Check out this SO thread.
Android: ListView elements with multiple clickable buttons
In the first answer on the page, he has a link to his blog which does a good job explaining and also has a link to the android developer page where they write a custom adapter.

Categories

Resources