I'm struggling with assigning my listview row more than one textview.
I want my row to have one textview for a person's name, one for address and one for age - but I'm not succeeding in doing so.
If someone could provide me with a simple example, that would be great.
Thanks!
Here's my custom ArrayAdapter
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater = null;
private ArrayList<Invoice> peopleList;
private final class ViewHolder {
TextView kidLabel;
TextView restLabel;
TextView fristLabel;
TextView amountLabel;
}
private ViewHolder mHolder = null;
public MyAdapter(Context context) {
Context mContext = context;
mInflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return peopleList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
mHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.row, null);
convertView.setTag(mHolder);
} else {
mHolder = (ViewHolder) convertView.getTag();
}
mHolder.kidLabel = (TextView) convertView.findViewById(R.id.kidLabel);
mHolder.kidLabel.setText(peopleList.get(position).getKID());
mHolder.fristLabel = (TextView) convertView
.findViewById(R.id.fristLabel);
mHolder.fristLabel.setText(peopleList.get(position).getDueDate());
mHolder.restLabel = (TextView) convertView.findViewById(R.id.restLabel);
mHolder.restLabel.setText(peopleList.get(position).getDueAmount());
mHolder.amountLabel = (TextView) convertView
.findViewById(R.id.amountLabel);
mHolder.amountLabel.setText(peopleList.get(position).getDueAmount());
return convertView;
}
}
And Here's my custom row xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ImageView
android:id="#+id/imageView1"
android:layout_width="fill_parent"
android:layout_height="45dip"
android:src="#drawable/cellback" android:scaleType="fitXY"/>
<TextView
android:id="#+id/kidLabel"
android:layout_width="160dip"
android:layout_height="25dip"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:textSize="13dip" android:textColor="#333"/>
<TextView
android:id="#+id/fristLabel"
android:layout_width="160dip"
android:layout_height="20dip"
android:layout_marginTop="25dip"
android:textSize="11dip" android:textColor="#999"/>
<TextView
android:id="#+id/amountLabel"
android:layout_width="160dip"
android:layout_height="25dip"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:textSize="13dip" android:layout_marginLeft="160dip" android:gravity="right" android:textColor="#333"/>
<TextView
android:id="#+id/restLabel"
android:layout_width="160dip"
android:layout_height="20dip"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:textSize="11dip" android:layout_marginLeft="160dip" android:layout_marginTop="25dip" android:gravity="right" android:textColor="#999"/>
</RelativeLayout>
First,you should create a xml to describe what your list cell likes,called cell.xml,for example:
<?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:orientation="vertical" android:background="#color/spink">
<TextView
android:id="#+id/name_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="#+id/address_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Address"
android:textAppearance="?android:attr/textAppearanceMedium" />
</LinearLayout>
Second,create a adapter.It helps your listview to show data:
public class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater = null;
private ArrayList<People> peopleList;
private final class ViewHolder {
TextView nameTextView;
TextView addressTextView;
}
private ViewHolder mHolder = null;
public MyAdapter(Context context) {
mContext = context;
mInflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public int getCount() {
return peopleList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
mHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.cell, null);
convertView.setTag(mHolder);
} else {
mHolder = (ViewHolder)convertView.getTag();
}
mHolder.nameTextView (TextView)convertView.findViewById(R.id.name_textView);
mHolder.nameTextView.setText(peopleList.get(position).getName());
mHolder.addressTextView = (TextView)convertView.findViewById(R.id.address_textView);
mHolder.addressTextView.setText(peopleList.get(position).getAddress());
return convertView;
}
}
Finally,when you want to show the data,do this in your activity:
listView.setAdapter(new MyAdapter());
hope it helps you.
You need to create a custom listview layout and a custom array adapter (I have also created a custom class to work with the layout).
An example of this is:
Custom class that works with the custom listview layout:
package id10778734.sceresini.week4.exercise3.views;
import id10778734.sceresini.week4.exercise3.R;
import id10778734.sceresini.week4.exercise3.Constants;
import id10778734.sceresini.week4.exercise3.tasks.Task;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
public class TaskListItem extends LinearLayout {
private Task mTask;
private ImageView mEmailImageView;
private ImageView mPriorityImageView;
private TextView mTaskNameTextView;
private TextView mTaskResponsibleTextView;
private ImageView mDeleteImageView;
public TaskListItem (Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onFinishInflate() {
super.onFinishInflate();
mEmailImageView = (ImageView) findViewById(R.id.list_row_layout_email_button);
mPriorityImageView = (ImageView) findViewById(R.id.list_row_layout_priority_icon);
mTaskNameTextView = (TextView) findViewById(R.id.list_row_layout_task_name);
mTaskResponsibleTextView = (TextView) findViewById(R.id.list_row_layout_responsible);
mDeleteImageView = (ImageView) findViewById(R.id.list_row_layout_delete_button);
}
public void setTask (Task task) {
mTask = task;
mEmailImageView.setTag(task);
switch (task.getPriority()) {
case Constants.LOW:
mPriorityImageView.setImageResource(R.drawable.low);
break;
case Constants.MEDIUM:
mPriorityImageView.setImageResource(R.drawable.medium);
break;
case Constants.HIGH:
mPriorityImageView.setImageResource(R.drawable.high);
break;
}
mTaskNameTextView.setText(task.getName());
mTaskResponsibleTextView.setText(task.getResponsible());
mDeleteImageView.setTag(task);
}
public Task getTask () {
return mTask;
}
public ImageView getDeleteImageView () {
return mDeleteImageView;
}
public ImageView getEmailImageView () {
return mEmailImageView;
}
}
the custom layout xml file:
<?xml version="1.0" encoding="UTF-8"?>
<id10778734.sceresini.week4.exercise3.views.TaskListItem
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dip" >
<ImageView
android:id="#+id/list_row_layout_email_button"
android:layout_width="36dip"
android:layout_height="36dip"
android:layout_gravity="center_vertical"
android:layout_marginLeft="4dip"
android:layout_marginRight="5dip"
android:contentDescription="#string/list_row_email_icon_description"
android:src="#android:drawable/ic_dialog_email" />
<ImageView
android:id="#+id/list_row_layout_priority_icon"
android:layout_width="24dip"
android:layout_height="24dip"
android:layout_gravity="center_vertical"
android:layout_marginLeft="4dip"
android:layout_marginRight="10dip"
android:contentDescription="#string/view_task_priority_icon_description" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" >
<TextView
android:id="#+id/list_row_layout_task_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/list_row_layout_responsible"
android:paddingRight="5dip"
android:textAppearance="#style/list_row_task_name" />
<TextView
android:id="#id/list_row_layout_responsible"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toLeftOf="#+id/list_row_layout_delete_button"
android:maxWidth="100dip"
android:textAppearance="#style/list_row_task_responsible" />
<ImageView
android:id="#id/list_row_layout_delete_button"
android:layout_width="36dip"
android:layout_height="36dip"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"
android:contentDescription="#string/delete_task_icon_description"
android:src="#drawable/task_delete" />
</RelativeLayout>
</id10778734.sceresini.week4.exercise3.views.TaskListItem>
And the custom array adapter:
package id10778734.sceresini.week4.exercise3;
import id10778734.sceresini.week4.exercise3.R;
import id10778734.sceresini.week4.exercise3.tasks.Task;
import id10778734.sceresini.week4.exercise3.views.TaskListItem;
import java.util.ArrayList;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class TaskListAdapter extends BaseAdapter
{
private ArrayList<Task> mTasks;
private Context mContext;
private AlertDialog unsavedChangesDialog;
private TaskManagerApplication mApp;
public TaskListAdapter(Context context, ArrayList<Task> tasks) {
super();
mApp = (TaskManagerApplication) context.getApplicationContext();
mContext = context;
mTasks = tasks;
}
#Override
public int getCount()
{
return mTasks.size();
}
#Override
public Task getItem(int position)
{
return (null == mTasks) ? null : mTasks.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
TaskListItem tli;
if (null == convertView)
{
tli = (TaskListItem) View.inflate(mContext, R.layout.list_row_layout, null);
} else
{
tli = (TaskListItem) convertView;
}
tli.setTask(mTasks.get(position));
tli.getEmailImageView().setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
emailTask(v);
}
});
tli.getDeleteImageView().setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v)
{
deleteTask(v);
}
});
return tli;
}
/**
* deleteTask() prompts the user with an alert dialog and presents them with
* the option to continue with the delete request or to cancel the request.
* Upon confirmation, the selected Task object which is retrieved from the
* deleteTaskIcon tag, will be removed from the list of currentTasks.
*
* #param v
*/
protected void deleteTask(View v)
{
final Task t = (Task) v.getTag();
String alertMessage = String.format(mContext.getString(R.string.delete_task_message), t.getName());
unsavedChangesDialog = new AlertDialog.Builder(mContext).setTitle(R.string.delete_task_title).setMessage(alertMessage)
// Delete the task and refresh the adapter.
.setPositiveButton(R.string.delete_task_delete, new AlertDialog.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1)
{
// Remove task from array list
mTasks.remove(t);
// Remove task from Database
mApp.deleteTask(t);
// Display toast message stating the task was deleted
mApp.displayToast(Constants.TASK_DELETED);
// Update listView with modified adapter
forceReload();
}
})
// Cancel the delete request and do nothing.
.setNegativeButton(R.string.delete_task_cancel, new AlertDialog.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1)
{
unsavedChangesDialog.cancel();
}
}).create();
unsavedChangesDialog.show();
}
/**
* emailTask() populates the selected task into an intent which allows the
* user to select a client to send the task. This is formatted for email
* clients.
*
* #param v
*/
protected void emailTask(View v)
{
// Retrieve the task that is allocated to this RowView
final Task t = (Task) v.getTag();
// Instantiate the intent that will be used to call the email client
Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);
// Variables/Arrays to hold email attributes
String[] emailRecipients = { mContext.getString(R.string.email_task_to_email) };
String emailType = mContext.getString(R.string.email_task_type);
String emailTitle = mContext.getString(R.string.email_task_title);
String emailSubject = String.format(mContext.getString(R.string.email_task_subject), t.getName());
String emailMessage = String.format(mContext.getString(R.string.email_task_message), t.getResponsible(), t.getName(), mContext.getString(t.getPriorityStringId()));
// Add the email attributes to the intent
emailIntent.setType(emailType);
emailIntent.putExtra(android.content.Intent.EXTRA_EMAIL, emailRecipients);
emailIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, emailSubject);
emailIntent.putExtra(android.content.Intent.EXTRA_TEXT, emailMessage);
// Start intent
mContext.startActivity(Intent.createChooser(emailIntent, emailTitle));
}
/**
* Refreshes the ListView with the modified dataset.
*/
public void forceReload()
{
notifyDataSetChanged();
}
}
Related
I currently have a grid view using a base adapter inside a fragment and I am trying to transfer to a different fragment when one of the items is clicked but none of the solutions I found on stack overflow has worked. I might miss something.
Adapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.licenta.joberfrontend.R;
import com.licenta.joberfrontend.rest.backend_entieties.Category;
import java.util.ArrayList;
import java.util.List;
public class CategoriesAdapter extends BaseAdapter {
public class ViewHolder {
TextView textName;
ImageView imageView;
}
private ArrayList<Category> categoryList;
public Context context;
public CategoriesAdapter(List<Category> apps, Context context) {
this.context = context;
this.categoryList = (ArrayList<Category>) apps;
}
#Override
public int getCount() {
return categoryList.size();
}
#Override
public Object getItem(int position) {
return position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View view, ViewGroup parent) // inflating the layout and initializing widgets
{
ViewHolder viewHolder;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.category_list_content, parent, false);
viewHolder = new ViewHolder();
viewHolder.textName = view.findViewById(R.id.textName);
viewHolder.imageView = view.findViewById(R.id.iconView);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
// here we are setting up the names and images
viewHolder.textName.setText(categoryList.get(position).getName());
viewHolder.imageView.setImageResource(this.context.getResources().getIdentifier(categoryList.get(position).getCategoryIconId(), "mipmap", this.context.getPackageName()));
return view;
}
}
Fragment's OnCreate
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final LocalStorageSaver localStorageSaver = new LocalStorageSaver(Objects.requireNonNull(getContext()));
final ToastShower toastShower = new ToastShower();
//REST services creation
final RetrofitCreator retrofitCreator = new RetrofitCreator();
final Retrofit retrofit = retrofitCreator.getRetrofit();
final CategoryService categoryService = retrofit.create(CategoryService.class);
final Call<List<Category>> getCategoriesRequest = categoryService.getAllCategoriesAndTheirJobs(localStorageSaver.getValueFromStorage(Constants.TOKEN));
getCategoriesRequest.enqueue(
new Callback<List<Category>>() {
#Override
public void onResponse(Call<List<Category>> call, Response<List<Category>> response) {
toastShower.showToast("Categories succesfully retrieved from backend.", getContext());
final GridView gridView = Objects.requireNonNull(getView()).findViewById(R.id.gridViewNewContract);
gridView.setAdapter(new CategoriesAdapter(response.body(), getActivity()));
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
toastShower.showToast("There has been a problem with retrieving the categories data!", getContext());
}
}
);
}
Items inside the grid view
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:layout_width="100dp"
android:layout_height="100dp"
app:cardCornerRadius="15dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_horizontal|center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginTop="15dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="15dp"
android:orientation="vertical">
<ImageView
android:id="#+id/iconView"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="center_horizontal"
android:src="#mipmap/ic_list"
android:tint="#color/colorAccent" />
<TextView
android:id="#+id/textName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:fontFamily="sans-serif"
android:maxLength="12"
android:text="#string/appName"
android:textColor="#color/colorAccent"
android:textSize="13sp" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
If you need any more information I will gladly provided.
I can mention that I've tried placing listeners both in the adapter and in the fragment directly on the grid.
please try this
viewHolder.imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//do stuff
}
});
This is may XML class random values in which we make a row that I want to delete
randomvalues.xml
<LinearLayout
android:id="#+id/linear"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_below="#+id/addbtn">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/img"
android:layout_width="30dp"
android:layout_height="40dp"
android:src="#drawable/img1"
/>
<LinearLayout
android:layout_width="255dp"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Name"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#339966"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/adress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Address"
android:textColor="#606060" />
</LinearLayout>
</LinearLayout>
<ImageButton
android:id="#+id/removebtn"
android:layout_width="30dp"
android:layout_height="40dp"
android:src="#drawable/remove"/>
</LinearLayout>
</LinearLayout>
this is my activity_main XML in which i used a list view to show a row that I make in random values XML file
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.chaqeel.taskviews.MainActivity">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/linear">
<ImageButton
android:id="#+id/addbtn"
android:layout_width="30dp"
android:layout_height="40dp"
android:src="#drawable/add"
android:layout_marginLeft="280dp"/>
</LinearLayout>
<ListView
android:id="#+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/linear"
>
</ListView>
</RelativeLayout>
This is MainActivity.java in which we used a array to show the values
MainActivity.java
package com.example.chaqeel.taskviews;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Collections;
public class MainActivity extends Activity {
ListView lv;
String[] Names = {"Aqeel", "Ali", "Ansar", "Usama", "Farhad"};
String[] Address = {"Chakwal", "Rawalpindi", "Islamabad", "Lahore",
"Multan"};
int[] Images = {R.drawable.img1, R.drawable.img2, R.drawable.img3,
R.drawable.img4, R.drawable.img5};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv = (ListView) findViewById(R.id.listview);
lv.setAdapter(new dataListAdapter(Names, Address, Images));
}
class dataListAdapter extends BaseAdapter {
String[] Name, Addres;
int[] imge;
/*dataListAdapter() {
Name = null;
Addres = null;
imge=null;
}*/
public dataListAdapter(String[] text, String[] text1, int[] text3) {
Name = text;
Addres = text1;
imge = text3;
}
public int getCount() {
return Name.length;
}
public Object getItem(int arg0) {
return null;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, ViewGroup
parent) {
LayoutInflater inflater = getLayoutInflater();
final View row;
row = inflater.inflate(R.layout.randomvalues, parent, false);
final TextView Name, Addres;
ImageView imge;
Name = (TextView) row.findViewById(R.id.name);
Addres = (TextView) row.findViewById(R.id.adress);
imge = (ImageView) row.findViewById(R.id.img);
Name.setText(Names[position]);
Addres.setText(Address[position]);
imge.setImageResource(Images[position]);
final ArrayList<String> lvv= new ArrayList<>();
Collections.addAll(lvv,Names);
// Collection.addAll(lvv,Address);
ImageButton dltbutton = (ImageButton) findViewById(R.id.removebtn);
dltbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
lvv.remove(Names);
lvv.remove(Address);
notifyDataSetChanged();
}
});
return (row);
}
}
}
In the onClickListener try the following code
youradapter.notifyDataSetChanged();
In the deletebutton onClickListener try this
Names = ArrayUtils.removeElement(Names,Names[position]);
Address = ArrayUtils.removeElement(Address,Address[position]);
notifyDataSetChanged();
Though it is advised to use OOP concept like a class to hold the Arrays of Names,Address and Images.
Try below code:
dltbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Name = ArrayUtils.removeElement(Names, Names[position]);
Address = ArrayUtils.removeElement(Address, Address[position]);
imge = ArrayUtils.removeElement(imge, imge[position]);
notifyDataSetChanged();
}
});
change this:
ImageButton dltbutton = (ImageButton) findViewById(R.id.removebtn);
dltbutton.setTag(position);
dltbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Integer index = (Integer) view.getTag();
lvv.remove(index.intValue());
notifyDataSetChanged();
}
});
Are you from Chakwal? I am Chakwalian. Again StackOverflow is telling me that my answer does not meet thier quality requirements.
You need to better idea to use Model class as below:-
create a model class MyModel.class
import java.util.ArrayList;
import java.util.List;
public class MyModel {
String Name, Address;
int image;
public MyModel(String name, String address, int image) {
Name = name;
Address = address;
this.image = image;
}
public String getName() {
return Name;
}
public String getAddress() {
return Address;
}
public int getImage() {
return image;
}
}
and then add with adapter class see below:
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends Activity {
ListView lv;
String[] Names = {"Aqeel", "Ali", "Ansar", "Usama", "Farhad"};
String[] Address = {"Chakwal", "Rawalpindi", "Islamabad", "Lahore",
"Multan"};
int[] Images = {R.drawable.ic_menu_camera, R.drawable.ic_menu_gallery, R.drawable.ic_menu_manage,
R.drawable.ic_menu_send, R.drawable.ic_menu_share};
private List<MyModel> myModel=new ArrayList<>();
private DataListAdapter dataListAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_main);
lv = (ListView) findViewById(R.id.listview);
for(int i=0;i<Names.length;i++){
myModel.add( new MyModel(Names[i],Address[i],Images[i]));
}
dataListAdapter=new DataListAdapter(myModel);
lv.setAdapter(dataListAdapter);
}
class DataListAdapter extends BaseAdapter {
private List<MyModel> myModel=new ArrayList<>();
public DataListAdapter(List<MyModel> myModel) {
this.myModel=myModel;
}
public int getCount() {
return myModel.size();
}
public Object getItem(int arg0) {
return null;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View convertView, final ViewGroup
parent) {
LayoutInflater inflater = getLayoutInflater();
final View row;
row = inflater.inflate(R.layout.randomevalue, parent, false);
final TextView Name, Addres;
ImageView imge;
Name = (TextView) row.findViewById(R.id.name);
Addres = (TextView) row.findViewById(R.id.adress);
imge = (ImageView) row.findViewById(R.id.img);
Name.setText(myModel.get(position).getName());
Addres.setText(myModel.get(position).getAddress());
imge.setImageResource(myModel.get(position).getImage());
ImageButton dltbutton = (ImageButton) row.findViewById(R.id.removebtn);
dltbutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
myModel.remove(position);
notifyDataSetChanged();
}
});
return (row);
}
}
public void addMore(View v)
{
myModel.add( new MyModel("Mahesh","India",R.drawable.ic_menu_share));
dataListAdapter.notifyDataSetChanged();
}
}
public void addMore(View v)
{
myModel.add( new MyModel("Mahesh","India",R.drawable.ic_menu_share));
dataListAdapter.notifyDataSetChanged();
}
add android:onClick="addMore" to your add button
it will fine Happy Coding :)
#Override
public boolean onContextItemSelected(MenuItem item) {
// TODO Auto-generated method stub
AdapterContextMenuInfo info =(AdapterContextMenuInfo) item.getMenuInfo();
pos=info.position;
deleteditem=myList.get(pos);
if(item.getTitle()=="Delete")
{
String delete = myList.get(pos);
File f = new File(path + "/"+ delete);
if (f != null && f.exists())
{
f.delete();
}
myList.remove(pos);
adapter. notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "item has deleted",Toast.LENGTH_LONG).show();
}
In my app I have 3 views
ImagiveView
TextView
Button
ImagView displays image accordingly, TextView and Button display names and number accordingly. But the problem is when I click on the button it does not call to the number which is displaying on the button. Although it does open the android caller app.
Telephone numbers are in string.xml file.
Here I provide my all files. Please help me
strings.xml
<string-array name="names">
<item>Abdul Malik</item>
<item>Adeel ur Rehman</item>
<item>Asad Majeeb</item>
<item>Ata ul Salam</item>
<item>Atta ul Qadir</item>
<item>Bilal Scunder</item>
<item>Chaudry Adnan Ahmed</item>
<item>Chaudry Imran</item>
<item>Ejaz Ahmed Saroya</item>
<item>Hamid Joya</item>
</string-array>
<string-array name="telephones">
<item>0000000000</item>
<item>0486607636</item>
<item>0485256515</item>
<item>0485128196</item>
<item>0465922084</item>
<item>0487150005</item>
<item>0488627993</item>
<item>0484783792</item>
<item>0484688663</item>
<item>0497697050</item>
</string-array>
MainActivity.xml
package com.example.android.listview_with_custom_layout;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ListView;
public class MainActivity extends ActionBarActivity {
ListView listView;
int [] movie_poster_resource={
R.drawable.movie_1,
R.drawable.movie_2,
R.drawable.movie_3,
R.drawable.movie_4,
R.drawable.movie_5,
R.drawable.movie_6,
R.drawable.movie_7,
R.drawable.movie_8,
R.drawable.movie_9,
R.drawable.movie_10,
};
String [] names ={};
String [] telephones ={};
MoviesAdapter moviesAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView=(ListView) findViewById(R.id.list_view);
telephones =getResources().getStringArray(R.array.telephones);
names =getResources().getStringArray(R.array.names);
int i=0;
moviesAdapter= new MoviesAdapter(getApplicationContext(),R.layout.row_layout);
listView.setAdapter(moviesAdapter);
for(String titles: names){
MovieDataProvider movieDataProvider= new MovieDataProvider(movie_poster_resource[i], titles, telephones[i]);
moviesAdapter.add(movieDataProvider);
i++;
}
}
}
MoviesDataAdapter
package com.example.android.listview_with_custom_layout;
/**
* Created by temp on 2/11/2015.
*/
public class MovieDataProvider {
private int movie_poster_resource;
private String movie_title;
private String telePhone;
public MovieDataProvider(int movie_poster_resource, String movie_title, String telePhone) {
this.setMovie_poster_resource(movie_poster_resource);
this.setMovie_title(movie_title);
this.telePhone = telePhone;
}
public int getMovie_poster_resource() {
return movie_poster_resource;
}
public String getMovie_title() {
return movie_title;
}
public String getTelePhone() {
return telePhone;
}
public void setMovie_poster_resource(int movie_poster_resource) {
this.movie_poster_resource = movie_poster_resource;
}
public void setMovie_title(String movie_title) {
this.movie_title = movie_title;
}
public void setTelePhone(String telePhone) {
this.telePhone = telePhone;
}
}
MoviesAdapter
package com.example.android.listview_with_custom_layout;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
/**
* Created by temp on 2/11/2015.
*/
public class MoviesAdapter extends ArrayAdapter {
List list = new ArrayList();
MovieDataProvider dataProvider;
public MoviesAdapter(Context context, int resource) {
super(context, resource);
}
static class DataHandler {
ImageView Poster;
TextView title;
Button telePhone;
}
#Override
public void add(Object object) {
super.add(object);
list.add(object);
}
#Override
public int getCount() {
return this.list.size();
}
#Override
public Object getItem(int position) {
return this.list.get(position);
}
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View row;
row = convertView;
DataHandler handler;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.row_layout, parent, false);
handler = new DataHandler();
handler.Poster = (ImageView) row.findViewById(R.id.movie_poster);
handler.title = (TextView) row.findViewById(R.id.movie_title);
handler.telePhone = (Button) row.findViewById(R.id.btn_call);
row.setTag(handler);
} else {
handler = (DataHandler) row.getTag();
}
dataProvider = (MovieDataProvider) this.getItem(position);
handler.Poster.setImageResource(dataProvider.getMovie_poster_resource());
handler.title.setText(dataProvider.getMovie_title());
handler.telePhone.setText(dataProvider.getTelePhone());
handler.telePhone.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Intent to launch phone dialer
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + dataProvider.getTelePhone()));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
});
return row;
}
}
activity_main.xml
<LinearLayout 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:background="#ffffd953"
tools:context=".MainActivity">
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</ListView>
</LinearLayout>
row_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="80dp"
android:background="#000000"
android:orientation="vertical"
android:paddingTop="10dp">
<ImageView
android:id="#+id/movie_poster"
android:layout_width="100dp"
android:layout_height="75dp"
android:layout_alignParentLeft="true"
android:src="#drawable/movie_1" />
<TextView
android:id="#+id/movie_title"
android:layout_width="100dp"
android:layout_height="75dp"
android:layout_toRightOf="#+id/movie_poster"
android:gravity="center"
android:text="This is movie name"
android:textColor="#FFFFFF" />
<Button
android:id="#+id/btn_call"
android:layout_width="wrap_content"
android:layout_height="75dp"
android:layout_alignParentRight="true"
android:layout_toRightOf="#+id/movie_title"
android:gravity="center"
android:text="call"
android:textColor="#FFFF" />
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:layout_below="#+id/movie_poster"
android:background="#FFFF"></View>
</RelativeLayout>
you forgot to initialize the telephones string in your MainActivity, do same as you did for movie_poster_resource after this it should work, and dont forgot to add permission
<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>
and last you can update the button click code with
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:"+dataProvider.getTelePhone()));
startActivity(callIntent);
and update your AdapterClass with this
public class MoviesAdapter extends ArrayAdapter {
List list = new ArrayList();
public MoviesAdapter(Context context, int resource) {
super(context, resource);
}
static class DataHandler {
ImageView Poster;
TextView title;
Button telePhone;
}
#Override
public void add(Object object) {
super.add(object);
list.add(object);
}
#Override
public int getCount() {
return this.list.size();
}
#Override
public Object getItem(int position) {
return this.list.get(position);
}
#Override
public View getView(int position, View convertView, final ViewGroup parent) {
View row;
row = convertView;
final MovieDataProvider dataProvider = (MovieDataProvider) this.getItem(position);;
DataHandler handler;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) this.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
row = inflater.inflate(R.layout.row_layout, parent, false);
handler = new DataHandler();
handler.Poster = (ImageView) row.findViewById(R.id.movie_poster);
handler.title = (TextView) row.findViewById(R.id.movie_title);
handler.telePhone = (Button) row.findViewById(R.id.btn_call);
} else {
handler = (DataHandler) row.getTag();
}
handler.Poster.setImageResource(dataProvider.getMovie_poster_resource());
handler.title.setText(dataProvider.getMovie_title());
handler.telePhone.setText(dataProvider.getTelePhone());
handler.telePhone.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:" + dataProvider.getTelePhone()));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
}
});
row.setTag(handler);
return row;
}
}
I try to make a custom view but I've got a problem with the spinner.
When I launch the application everything is ok. Preferences are read and the spinner setSelection method work great (display picture is ok).
When I change the spinner value, there is no problem too : Preferences are saved and when I start the application the new choice is display.
My problem comes when rotating the device, all my spinner value are reset to the last spinner value (vv2 in my code). I really don't understand...
Here is my code :
The widget_value_view.xml
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
<Spinner
android:id="#+id/my_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:background="#android:color/transparent" />
<TextView
android:id="#+id/my_value_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_centerVertical="true"
android:background="#android:color/transparent" />
</merge>
The ValueView.java class :
package com.example.spinnertest;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
public class ValueView extends LinearLayout {
protected TextView mValueTv = null;
protected Spinner mSpinner = null;
protected List<String> mChoiceList;
private MySpinnerAdapter mSpinnerAdapter;
public ValueView(Context context) {
super(context);
}
public ValueView(Context context, AttributeSet attributes){
super(context,attributes);
TypedArray a = context.getTheme().obtainStyledAttributes(attributes,R.styleable.ValueView,0, 0);
try {
String valueList = a.getString(R.styleable.ValueView_valueList);
mChoiceList = Arrays.asList(valueList.split("\\|"));
} finally {
a.recycle();
}
setOrientation(LinearLayout.HORIZONTAL);
setGravity(Gravity.CENTER_VERTICAL);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.widget_value_view, this, true);
mSpinner = (Spinner) getChildAt(0);
mValueTv = (TextView) getChildAt(1);
mSpinnerAdapter = new MySpinnerAdapter(context, mChoiceList);
mSpinner.setAdapter(mSpinnerAdapter);
}
/**
* Change textview value
*/
public void setValue(double value,String format){
mValueTv.setText("todo");
invalidate();
requestLayout();
}
/**
* Set the current item of the spinner
* #param position of the item
*/
public void setSelection(int position, boolean animate) {
// mSpinnerAdapter.notifyDataSetChanged();
mSpinner.setSelection(position,animate);
// invalidate();
// requestLayout();
}
public int getSelectedItemPosition() {
return mSpinner.getSelectedItemPosition();
}
}
In this class I use a adapter define with 2 layout and one class :
MySpinnerAdapter.java
package com.example.spinnertest;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MySpinnerAdapter extends BaseAdapter {
public static final String ITEM_ALTITUDE = "altitude";
public static final String ITEM_SPEED = "speed";
public static final String ITEM_DISTANCE = "distance";
private static final String LOG_TAG = "SPINNER_TEST";
private Context mContext;
private List<String> mChoiceList;
public MySpinnerAdapter(Context context, List<String> values) {
this.mContext = context;
this.mChoiceList = values;
}
#Override
public int getCount() {
return mChoiceList.size();
}
#Override
public Object getItem(int position) {
return mChoiceList.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater layout = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layout.inflate(R.layout.item_spinner_value, null);
}
ImageView imView = (ImageView) convertView.findViewById(R.id.item_spinner_value_iv);
Log.d(LOG_TAG,"Spinner Adapter position = " + String.valueOf(position));
imView.setImageResource(getSpinnerItemImage(position));
return convertView;
}
#Override
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater layout = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = layout.inflate(R.layout.item_spinner_list, null);
}
ImageView imView = (ImageView) convertView.findViewById(R.id.item_spinner_list_iv);
TextView textView = (TextView) convertView.findViewById(R.id.item_spinner_list_tv);
textView.setText(mChoiceList.get(position));
imView.setImageResource(getSpinnerItemImageSmall(position));
return convertView;
}
private int getSpinnerItemImageSmall(int position) {
String item = mChoiceList.get(position);
if (item.equals(ITEM_ALTITUDE)) {
return R.drawable.altitude_small;
} else if (item.equals(ITEM_DISTANCE)) {
return R.drawable.distance_small;
} else if (item.equals(ITEM_SPEED)) {
return R.drawable.vitesse_small;
} else {
return R.drawable.date_small;
}
}
private int getSpinnerItemImage(int position) {
String item = mChoiceList.get(position);
if (item.equals(ITEM_ALTITUDE)) {
return R.drawable.altitude;
} else if (item.equals(ITEM_DISTANCE)) {
return R.drawable.distance;
} else if (item.equals(ITEM_SPEED)) {
return R.drawable.vitesse;
} else {
return R.drawable.date;
}
}
}
and the 2 layout item_spinner_list.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:id="#+id/item_spinner_list_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:padding="5dp"
android:src="#android:drawable/ic_menu_gallery" />
<TextView
android:id="#+id/item_spinner_list_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:padding="5dp"
android:layout_toRightOf="#+id/item_spinner_list_iv"
android:text="Durée" />
</RelativeLayout>
and item_spinner_value.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"
android:background="#android:color/transparent" >
<ImageView
android:id="#+id/item_spinner_value_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:padding="5dp"
android:src="#android:drawable/ic_menu_gallery" />
</RelativeLayout>
and finally my MainActivity.java
package com.example.spinnertest;
import android.app.Activity;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
public class MainActivity extends Activity {
private SharedPreferences mPref;
private ValueView mVv1;
private ValueView mVv2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mVv1 = (ValueView)findViewById(R.id.value1);
mVv2 = (ValueView)findViewById(R.id.value2);
mVv1.setSelection(mPref.getInt("pref_val1", 0),false);
mVv2.setSelection(mPref.getInt("pref_val2", 1),false);
}
#Override
public void onPause() {
SharedPreferences.Editor editor = mPref.edit();
editor.putInt("pref_val1", mVv1.getSelectedItemPosition());
editor.putInt("pref_val2", mVv2.getSelectedItemPosition());
editor.commit();
super.onPause();
}
}
and the layout :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res/com.example.spinnertest"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.spinnertest.ValueView
android:id="#+id/value1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_margin="10dp"
android:background="#android:color/transparent"
custom:valueList="speed|altitude|distance" />
<com.example.spinnertest.ValueView
android:id="#+id/value2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_below="#+id/value1"
android:layout_margin="10dp"
custom:valueList="speed|altitude|distance" />
</RelativeLayout>
I cannot really explain why your code is not working, but I would prefer to save the state of the spinner locally (I mean in the activity); it's the normal Android workflow for screen rotation.
Something like this:
String MVV1="1";
String MVV2="2";
#Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
mPref = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
mVv1 = (ValueView)findViewById(R.id.value1);
mVv2 = (ValueView)findViewById(R.id.value2);
if (savedInstanceState != null) {
mVv1.setSelection(savedInstanceState.getInt(MVV1),false);
mVv2.setSelection(savedInstanceState.getInt(MVV2),false);
}
else{
mVv1.setSelection(mPref.getInt("pref_val1", 0),false);
mVv2.setSelection(mPref.getInt("pref_val2", 1),false);
}
}
#Override
public void onPause() {
SharedPreferences.Editor editor = mPref.edit();
editor.putInt("pref_val1", mVv1.getSelectedItemPosition());
editor.putInt("pref_val2", mVv2.getSelectedItemPosition());
editor.commit();
super.onPause();
}
#Override
protected void onSaveInstanceState (Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(MVV1, mVv1.getSelectedItemPosition());
outState.putInt(MVV2, mVv2.getSelectedItemPosition());
}
My syntax is maybe not perfect because I wrote it in the SO editor but hope you got the idea: the status is written in the Preferences as soon as the Activity is paused but if the activity rotates (your method should work but maybe is there a cache to access to the preferences or something...) then, it'll use the specific bundle for it: the one which is filled just when the screen rotates and used when the screen is recreated.
Test it and say if it's working ;)
So I have the following view
list_view_item.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layoutSessionItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/lblGroupDate"
style="#style/CustomText.GrayTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</TextView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="#+id/lblCourseCode"
style="#style/CustomText.GrayText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/lblSessionCode"
style="#style/CustomText.GrayText"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
So basically I get the following data from the database:
COURSE_CODE
SESSION_CODE
SESSION_DATE
I need to group the ListView items by SESSION_DATE, what I do is I keep a variable called "PreviousDate" and I compare it to the current SESSION_DATE, if it's different then I enable the header with the ID: "lblGroupDate" if the dates are the same I Hide "lblGroupDate".
Here's my Adapter:
public class SessionListAdapter extends BaseAdapter {
private Date PreviousDate = new Date();
static class ViewHolder {
TextView lblGroupDate;
TextView lblCourseCode;
TextView lblSessionCode;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = mLayoutInflater.inflate(R.layout.list_view_item, null);
holder = new ViewHolder();
holder.lblGroupDate = (TextView) convertView.findViewById(R.id.lblGroupDate);
holder.lblCourseCode = (TextView) convertView.findViewById(R.id.lblCourseCode);
holder.lblSessionCode = (TextView) convertView.findViewById(R.id.lblSessionCode);
} else {
holder = (ViewHolder)convertView.getTag();
}
SessionData session = (SessionData) getItem(position);
if(session != null) {
Date sessionDate = session.SESSION_DATE;
if (!mPrevDate.equals(sessionDate)) {
PreviousDate = sessionDate;
// HIDE GROUP HEADER
holder.lblGroupDate.setVisibility(View.GONE);
}
else {
// SHOW GROUP HEADER
holder.lblGroupDate.setVisibility(View.VISIBLE);
}
holder.lblCourseCode.setText(session.COURSE_CODE);
holder.lblSessionCode.setText(session.SESSION_CODE);
}
}
}
Here's the PROBLEM:
Lets say I have 20 records, when I scroll down and then scroll up again the rows that had the Group Header (lblGroupDate) enabled get shifted up without a header, it's the header was shifted to the next 3 rows. Why is this happening?
It's happening because getView() can be called at anytime and out-of-order from your data-set. You need to create a data-set that the adapter can be backed by. Just sorting your adapter out. Will update answer with code in a moment.
SessionListAdapter.java
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class SessionListAdapter extends BaseAdapter
{
private static final int TYPE_GROUP = 0;
private static final int TYPE_SESSION = 1;
private static final int MAX_TYPES = 2;
private final LayoutInflater mLayoutInflater;
private ArrayList<SessionViewData> mData;
public SessionListAdapter(Context context, List<SessionData> sessionData)
{
mLayoutInflater = LayoutInflater.from(context);
updateSessionViewData(sessionData);
}
public void updateSessionViewData(List<SessionData> sessionData)
{
Date previousDate = new Date();
ArrayList<SessionViewData> data = new ArrayList<SessionViewData>();
for(SessionData session: sessionData){
if(!previousDate.equals(session.SESSION_DATE)){
data.add(new SessionViewData(TYPE_GROUP, session));
previousDate = session.SESSION_DATE;
}
data.add(new SessionViewData(TYPE_SESSION, session));
}
mData = data;
notifyDataSetChanged();
}
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
SessionViewData data = mData.get(position);
if(convertView == null){
final int layoutId;
switch(data.type){
case TYPE_GROUP: layoutId = R.layout.list_session_group; break;
case TYPE_SESSION: layoutId = R.layout.list_session_item; break;
default:
throw new IllegalArgumentException("Bad type for: " + data.session);
}
convertView = mLayoutInflater.inflate(layoutId, parent, false);
}
switch(data.type){
case TYPE_GROUP:
TextView lblGroupDate = ((TextView)convertView.findViewById(R.id.lblGroupDate));
lblGroupDate.setText(DateUtils.formatDateTime(convertView.getContext(),
data.session.SESSION_DATE.getTime(), DateUtils.FORMAT_SHOW_DATE));
break;
case TYPE_SESSION:
TextView lblCourseCode = (TextView)convertView.findViewById(R.id.lblCourseCode);
lblCourseCode.setText(data.session.COURSE_CODE);
TextView lblSessionCode = (TextView)convertView.findViewById(R.id.lblSessionCode);
lblSessionCode.setText(data.session.SESSION_CODE);
break;
}
return convertView;
}
#Override
public Object getItem(int position)
{
return mData.get(position);
}
#Override
public long getItemId(int position)
{
return position;
}
#Override
public int getItemViewType(int position)
{
return mData.get(position).type;
}
#Override
public int getViewTypeCount()
{
return MAX_TYPES;
}
#Override
public int getCount()
{
return mData.size();
}
static class SessionViewData
{
int type;
SessionData session;
public SessionViewData(int type, SessionData session)
{
this.type = type;
this.session = session;
}
}
}
list_session_group.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lblGroupDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/CustomText.GrayTitle"
/>
list_session_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/layoutSessionItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
>
<TextView
android:id="#+id/lblCourseCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/CustomText.GrayText"
/>
<TextView
android:id="#+id/lblSessionCode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="#style/CustomText.GrayText"
/>
</LinearLayout>