As my post states, I can't seem to get my ArrayAdapter to update the whole list despite the call "adapter.notifyDataSetChanged();" Only the last element in the list is updated.
Can someone maby see what I'm doing wrong below??
Here is my custom adapter
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class WeatherAdapter extends ArrayAdapter<Weather>{
Context context;
int layoutResourceId;
Weather data[] = null;
private WeatherHolder holder;
private Weather weather;
public WeatherAdapter(Context context, int layoutResourceId, Weather[] data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new WeatherHolder();
holder.imgIcon = (TextView)row.findViewById(R.id.imgen);
holder.txtTitle = (TextView)row.findViewById(R.id.txtTitle);
row.setTag(holder);
}
else
{
holder = (WeatherHolder)row.getTag();
}
weather = data[position];
holder.txtTitle.setText(weather.getName());
//holder.imgIcon.setText(Double.toString(weather.getBuyingRate()));
return row;
}
public void update(String buttonPressed){
if(buttonPressed == "Köp Kurs"){
holder.imgIcon.setText(Double.toString(weather.getBuyingRate()));//This updates only the last element in list but I want to update every element in the list
}
else if(buttonPressed == "Antal"){ holder.imgIcon.setText(Double.toString(weather.getNrOfSharesInPortfolio()));//This updates only the last element in list but I want to update every element in the list
}
}
static class WeatherHolder
{
TextView imgIcon;
TextView txtTitle;
}
}
And here is my main class, when I call "Update()" method only the last element in the list is updated but not the others. How can I update the whole list instead of just the last element in the list?
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ListView;
public class MainActivity extends Activity {
private ListView listView1;
private Button goButton;
private String[] listheader = {"Köp Kurs","Antal"};
private WeatherAdapter adapter;
private int totalElemInlist = listheader.length;
private int currentelemInList=0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Weather weather_data[] = new Weather[]
{
new Weather("ABB", 56.0, 300),
new Weather("Volvo", 89.0,500),
new Weather("Astra Zeneca", 98.55, 50)
};
adapter = new WeatherAdapter(this,
R.layout.listview_item_row, weather_data);
listView1 = (ListView)findViewById(R.id.listView1);
View header = (View)getLayoutInflater().inflate(R.layout.listview_header_row, null);
listView1.addHeaderView(header);
goButton = (Button) findViewById(R.id.testButton);
goButton.setText(listheader[currentelemInList]);
listView1.setAdapter(adapter);
goButton.setOnClickListener(new OnClickListener() {
public void onClick(View view) {
String buttonPressed = (String) ((Button) view).getText();
goThroughList(buttonPressed);
System.out.println("Button Clicked" + buttonPressed);
}
});
}
private void goThroughList(String buttonPressed){
currentelemInList++;
if(currentelemInList>=totalElemInlist){
currentelemInList=0;
}
goButton.setText(listheader[currentelemInList]);
if(buttonPressed == "Köp Kurs"){
System.out.println("Köp kurs");
adapter.update(buttonPressed);
adapter.notifyDataSetChanged();//This only updates the last element in list
}
else if(buttonPressed == "Antal"){
System.out.println("Antal");
adapter.update(buttonPressed);
adapter.notifyDataSetChanged();//This only updates the last element in list
}
System.out.println(currentelemInList);
}
}
How can I update the whole list instead of just the last element in the list?
You must make your changes happen in getView(). getView() redraws every row as they appear whenever the user scrolls the ListView or notifyDataSetChanged() is called. So the changes must happen in there otherwise they will be erased.
First create a new field variable in your adapter:
private String currentImage;
Second change update() to control the contents on imgIcon:
public void update(String buttonPressed){
currentImage = buttonPressed;
notifyDataSetChanged();
}
Last change getView() to display the current images for each row:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
...
weather = data[position];
holder.txtTitle.setText(weather.getName());
if(currentImage.equals("Köp Kurs")){
holder.imgIcon.setText(Double.toString(weather.getBuyingRate()));
}
else if(currentImage.equals("Antal")){
holder.imgIcon.setText(Double.toString(weather.getNrOfSharesInPortfolio()));
}
return row;
}
(You can also simplify goThroughList(), since the if-else contains the exact same code.)
You should compare string like this.
buttonPressed.equals("Köp Kurs")
I might be wrong , but I think problem is because you are holding only last element in your holder. The member variable "holder" in adapter should be array or list, and you should hold all element, and in update method you should iterate through holder array and change the text
public void update(String buttonPressed){
for(int index =0 ; index < holder.size();index++){
if(buttonPressed == "Köp Kurs"){
holder[index].imgIcon.setText(Double.toString(weather.getBuyingRate()));//This updates only the last element in list but I want to update every element in the list
}
else if(buttonPressed == "Antal"){ holder[index].imgIcon.setText(Double.toString(weather.getNrOfSharesInPortfolio()));//This updates only the last element in list but I want to update every element in the list
}
This should solve your problem
Related
following is my Java code in Android Studio. GUI Layout contain an editText where a word is to be input and then click on search button. After that, it will show the matching words from an array (which contain words) and display those in a listView. The functionality of fetching matching regex from array and then displaying item by item in listView is to be implemented; I need idea about that how to implement it in Finder function.
Example 1:
Array of Words : "Dust", "Duff", "Thrust", "Man", "Grade", "Mole", "Tax"
Input: ust
Output in listView:
Item 1: Dust
Item 2: Thrust
package com.neatsoft.hamqafia;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
public class MainActivity extends AppCompatActivity {
EditText textBar;
Button findBtn;
ListView listView;
String words[] = {"Dust", "Duff", "Thrust", "Man", "Grade", "Mole", "Tax"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
private void Init(){
textBar = (EditText) findViewById(R.id.editText);
findBtn = (Button) findViewById(R.id.button);
listView = (ListView) findViewById(R.id.listView);
}
private void Finder(String toFind){
//Store Array in Trie Datastructure and then find toFind keyword and show the results item by item in listView
///OR create regex search by any other datastructure or methodology
}
}
when clicked the search button .you can search text in list items with String str1.toLowerCase().contains(str2.toLowerCase()) and save strings that contains search key in another list or array .after that reload data to listview with search list items .
note : you can use another button (clear search) and when click it, assign searchlist variable to initial list and reload data .(no search case)
private void Finder(String toFind){
if(searchList == null) {
searchList = new ArrayList<>();
}
searchList.clear();
if(toFind != null || !toFind.trim().equals("")) {
for(String str : words) {
if(str.toLowerCase().contains(toFind.toLowerCase()))
searchList.add(str);
}
}
notifyDataToListView();
}
private void notifyDataToListView() {
if(adapter == null) {
adapter = new BaseAdapter() {
#Override
public int getCount() {
return searchList == null ? 0 : searchList.size();
}
#Override
public Object getItem(int position) {
return null;
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = new TextView(getApplicationContext());
}
((TextView) convertView).setText(searchList.get(position));
return null;
}
};
myListView.setAdapter(adapter);
}else {
adapter.notifyDataSetChanged();
}
}
like this.Define a BaseAdapter object globally.
I've a problem with listview in android, I've created a list view that takes data from SQLite database with a custom ArrayAdapter
I want to display an image view when user choose an item, but when I click on an item, the image (check mark) shows in 3 other items
I don't know where is the problem exactly, here is my code for adapter :
import info.androidhive.tabsswipe.R;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.itdinamik.tabswipe.CompareVehicle;
import com.itdinamik.vcompare.MySQLiteHelper;
import com.itdinamik.vcompare.Vehicle;
public class ComperAdapter extends ArrayAdapter<Vehicle>{
List<Vehicle> data;
Context context;
int layoutResID;
Vehicle itemdata;
MySQLiteHelper dbhelper;
public ComperAdapter(Context context, int layoutResourceId, List<Vehicle> data) {
super(context, layoutResourceId, data);
this.data=data;
this.context=context;
this.layoutResID=layoutResourceId;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final NewsHolder holder;
View row = convertView;
dbhelper = new MySQLiteHelper(context);
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResID, parent, false);
holder = new NewsHolder();
holder.itemNameTitle = (TextView)row.findViewById(R.id.VehicleTxt);
holder.itemNameScore = (TextView)row.findViewById(R.id.Score);
holder.CheckedMark=(ImageView)row.findViewById(R.id.Checked);
holder.Vehicle=(ImageView)row.findViewById(R.id.Vehicle);
holder.RL = (RelativeLayout)row.findViewById(R.id.Rv);
row.setTag(holder);
}
else
{
holder = (NewsHolder)row.getTag();
}
//Toast.makeText(getContext(), String.valueOf(position +" - " + CompareVehicle.ClickedItem), Toast.LENGTH_SHORT).show();
if(CompareVehicle.ItemClieckd) {
if(position == CompareVehicle.ClickedItem) {
Log.w("Position", String.valueOf(position));
holder.CheckedMark.setVisibility(View.VISIBLE);
holder.RL.setBackgroundColor(Color.rgb(201, 50, 39));
}
}
itemdata = data.get(position);
holder.itemNameTitle.setText(itemdata.getTitle() + " - " + itemdata.getKraj() + " - "+ String.valueOf(position) + " - " + CompareVehicle.ClickedItem);
double totaldefault = itemdata.getOhranjenost()*0.25+itemdata.getPrevozeni()*0.16+
itemdata.getServis()*0.14+ itemdata.getCena()*0.13+
itemdata.getPoraba()*0.11+ itemdata.getStarost()*0.08+
itemdata.getDodatna()*0.07+ itemdata.getCenaZav()*0.06;
holder.itemNameScore.setText(String.format("%.1f",totaldefault));
return row;
}
static class NewsHolder{
TextView itemNameTitle;
TextView itemNameScore;
ImageView CheckedMark, Vehicle;
RelativeLayout RL;
}
}
and this one is for my fragment that i use to show my list view
import info.androidhive.tabsswipe.R;
import java.util.ArrayList;
import java.util.List;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.itdinamik.tabswipe.adapter.ComperAdapter;
import com.itdinamik.vcompare.MySQLiteHelper;
import com.itdinamik.vcompare.Vehicle;
public class CompareVehicle extends Fragment{
ViewPager mViewPager;
ArrayList<Vehicle> DataList;
static MySQLiteHelper dbhelper;
ComperAdapter adapter;
List<Vehicle> itemData;
ListView lv;
Button CompareButton;
int ClickedNum = 0;
public static int ClickedItem;
public static boolean ItemClieckd = false;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_compare_vehicle, container, false);
lv = (ListView)rootView.findViewById(R.id.CompareList);
CompareButton = (Button)rootView.findViewById(R.id.CompareButton);
dbhelper = new MySQLiteHelper(getActivity());
// get all vehicles
itemData = dbhelper.getAllVehicles();
adapter=new ComperAdapter(getActivity(),R.layout.list_single,itemData);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int position,
long arg3) {
// TODO Auto-generated method stub
ClickedItem = position;
ItemClieckd = true;
ClickedNum += 1;
adapter.notifyDataSetChanged();
/*RelativeLayout Rl = (RelativeLayout)arg1.findViewById(R.id.Rv);
ImageView CheckImg = (ImageView)arg1.findViewById(R.id.Checked);
Rl.setBackgroundColor(Color.rgb(201, 50, 39));
CheckImg.setVisibility(View.VISIBLE);*/
//Toast.makeText(getActivity(), String.valueOf(mSelectedItem), Toast.LENGTH_LONG).show();
}
});
CompareButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (ClickedNum < 2) {
Toast.makeText(getActivity(), "Please mark at least 2 items to compare them", Toast.LENGTH_LONG).show();
}
}
});
return rootView;
}
}
thank you
To avoid issues with view recycling in ListViews etc, I include a boolean for checked state in the item data List supplied to the constructor of the ArrayAdapter. I also provide my own interface for handling things like click events on child Views contained in my custom list item layout.
In my example below we handle a checkbox which can be clicked and also a label which can be long clicked:
public class MyListAdapter extends ArrayAdapter<MyItem> {
// interface for handling item child view events
public interface MyListAdapterListener {
void onItemCheckClicked(int index);
void onItemLabelLongClicked(int index);
}
private MyListAdapterListener mMyListAdapterListener;
int layoutResID;
// Constructor
public MyListAdapter(Context context, int resource, List<MyItem> myItems) {
super(context, resource, myItems);
layoutResID = resource;
}
public void setMyListAdapterListener(MyListAdapterListener listener) {
this.mMyListAdapterListener = listener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setup the row
View row;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
row = inflater.inflate(layoutResID, null);
} else {
row = convertView;
}
// setup the ViewHolder for this item
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
}
// setup this item's label view
holder.label.setText(getItem(position).label);
// tag this item's label view with position so it can be retrieved in the onLongClick
holder.label.setTag(position);
// set the OnLongClickListener for the this item's label view
holder.label.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActivityListListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemLabelLongClicked method
mActivityListListener.onItemLabelLongClicked((Integer)v.getTag());
}
return false;
}
});
// setup this item's checkbox view
holder.checkbox.setChecked(getItem(position).myItemCheckBoolean);
// tag this item's checkbox view with position so it can be retrieved in the onClick
holder.checkbox.setTag(position);
// set the OnClickListener for the this item's checkbox view
holder.checkbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMyListAdapterListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemCheckClicked method
mMyListAdapterListener.onItemCheckClicked((Integer) v.getTag());
}
}
});
return row;
}
class ViewHolder {
CheckBox checkbox = null;
TextView label = null;
ViewHolder(View row) {
this.checkbox = (CheckBox) row.findViewById(R.id.check_box);
this.label = (TextView) row.findViewById(R.id.item_label);
}
}
}
The MyItem class:
public class MyItem {
public String label;
public boolean myItemCheckBoolean;
}
Using the ArrayAdapter:
public class MyFragment extends Fragment {
....
private List<MyItem> myItems = new ArrayList<MyItem>();
....
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment__my_list, container, false);
lv = (ListView)rootView.findViewById(R.id.my_list);
// For example purposes, fill myItems with dummy data setting all checkboxes initially to false
for (int i = 0; i < 10; i++) {
MyItem myItem = new MyItem();
myItem.label = "Item " + i;
myItem.myItemCheckBoolean = false;
myItems.add(myItem);
}
MyListAdapter adapter = new MyListAdapter(getActivity(), R.layout.my_list_item, myItems);
adapter.setMyListAdapterListener( new MyListAdapter.MyListAdapterListener() {
#Override
public void onItemCheckClicked(int index) {
Log.d("MyFragment", "Item " + index + " Check Clicked");
// toggle the item's boolean
myItems.get(index).myItemCheckBoolean = !myItems.get(index).myItemCheckBoolean;
}
#Override
public void onItemLabelLongClicked(int index) {
Log.d("MyFragment", "Item " + index + " Label LongClicked");
}
}
lv.setAdapter(adapter);
....
return rootView;
}
Additional:
In response to your comment, you can use the adapter to customize the display of your list items as you wish. The version below shows how you might modify the adapter to use an ImageView instead of a CheckBox, and also changes the background color:
public class MyListAdapter extends ArrayAdapter<MyItem> {
// interface for handling item child view events
public interface MyListAdapterListener {
void onItemCheckClicked(int index);
void onItemLabelLongClicked(int index);
}
private MyListAdapterListener mMyListAdapterListener;
int layoutResID;
// Constructor
public MyListAdapter(Context context, int resource, List<MyItem> myItems) {
super(context, resource, myItems);
layoutResID = resource;
}
public void setMyListAdapterListener(MyListAdapterListener listener) {
this.mMyListAdapterListener = listener;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// setup the row
View row;
if (convertView == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
row = inflater.inflate(layoutResID, null);
} else {
row = convertView;
}
// setup the ViewHolder for this item
ViewHolder holder = (ViewHolder) row.getTag();
if (holder == null) {
holder = new ViewHolder(row);
row.setTag(holder);
}
// setup this item's label view
holder.label.setText(getItem(position).label);
// tag this item's label view with position so it can be retrieved in the onLongClick
holder.label.setTag(position);
// set the OnLongClickListener for the this item's label view
holder.label.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (mActivityListListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemLabelLongClicked method
mActivityListListener.onItemLabelLongClicked((Integer)v.getTag());
}
return false;
}
});
// setup this item's image view based on the current state of the boolean
if (getItem(position).myItemCheckBoolean) {
holder.image.setImageResource(R.drawable.image_a);
} else {
holder.image.setImageResource(R.drawable.image_b);
}
// tag this item's image view with position so it can be retrieved in the onClick
holder.image.setTag(position);
// set the OnClickListener for the this item's image view
holder.image.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mMyListAdapterListener != null) {
// retrieve position from the view's tag, and trigger the listeners onItemCheckClicked method
mMyListAdapterListener.onItemCheckClicked((Integer) v.getTag());
}
}
});
// setup this item's background based on the current state of the boolean
if (getItem(position).myItemCheckBoolean) {
holder.layout.setBackgroundColor(Color.red);
} else {
holder.layout.setBackgroundColor(Color.white);
}
return row;
}
class ViewHolder {
ImageView image = null;
TextView label = null;
RelativeLayout layout = null;
// constructor
ViewHolder(View row) {
this.image = (ImageView) row.findViewById(R.id.item_image);
this.label = (TextView) row.findViewById(R.id.item_label);
this.layout = (RelativeLayout) row.findViewById(R.id.item_layout)
}
}
}
I'm trying to figure out how to implement an infinitely scrolling list. It will display a calendar and events and it should start from now or selected date. It should be scrollable in both directions, past and future. The solutions with OnScrollListener here seem to work pretty well if I only need to go to future (index just grows bigger). But I don't see how I would go to the past.
This solution seems to be very wasteful for my case. getView is called thousands of times. Maybe ListView isn't the solution, and I'll have to go with lower-level code. Any ideas?
EDIT: getView being called thousands of times wasn't the fault of the latter solution. However, it still gets called too many times and with wrong values. If I set selection like this:
myList.setSelection(Integer.MAX_VALUE/2)
I get getView calls with indexes starting from zero. For example, I get getView calls like this:
getView pos 0
...
getView pos 26
and then
getView pos 1073741823
...
getView pos 1073741847
Which are the correct ones. Then:
getView pos 0
...
getView pos 26
again
This all happens before I scroll or touch the screen at all. Doesn't seem to make much sense.
Here is an implementation of this task.
EndlessScrollBaseAdapter.java
package com.example.endlessscrollinbothdirections;
import java.util.Map;
import android.content.Context;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.TextView;
/** A child class shall subclass this Adapter and implement method getDataRow(int position,
* View convertView, ViewGroup parent), which supplies a View present data in a ListRow.
* This parent Adapter takes care of displaying ProgressBar in a row or indicating that it
* has reached the last row. */
public abstract class EndlessScrollBaseAdapter<T> extends BaseAdapter implements
OnScrollListener {
private int mVisibleThreshold = 5;
// the main data structure to save loaded data
protected Map<Integer, T> mItems;
protected Context mContext;
// the serverListSize is the total number of items on the server side,
// which should be returned from the web request results
protected int mServerListSize = -1;
// Two view types which will be used to determine whether a row should be displaying
// data or a Progressbar
public static final int VIEW_TYPE_LOADING = 0;
public static final int VIEW_TYPE_ACTIVITY = 1;
public static final int VIRTUAL_MIDDLE_OFFSET = Integer.MAX_VALUE / 2;
public EndlessScrollBaseAdapter(Context context, Map<Integer, T> items) {
mContext = context;
mItems = items;
}
public void setServerListSize(int serverListSize) {
this.mServerListSize = serverListSize;
}
/** disable click events on indicating rows */
#Override
public boolean isEnabled(int position) {
return getItemViewType(position) == EndlessScrollBaseAdapter.VIEW_TYPE_ACTIVITY;
}
/** One type is normal data row, the other type is Progressbar */
#Override
public int getViewTypeCount() {
return 2;
}
/** the size of the List plus one, the one is the last row, which displays a
* Progressbar */
#Override
public int getCount() {
return Integer.MAX_VALUE;
}
/** return the type of the row, the last row indicates the user that the ListView is
* loading more data */
#Override
public int getItemViewType(int position) {
return mItems.containsKey(position
- EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET) ? EndlessScrollBaseAdapter.VIEW_TYPE_ACTIVITY
: EndlessScrollBaseAdapter.VIEW_TYPE_LOADING;
}
#Override
public T getItem(int position) {
return mItems.get(position - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET);
}
#Override
public long getItemId(int position) {
return position;
}
/** returns the correct view */
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == EndlessScrollBaseAdapter.VIEW_TYPE_LOADING) {
return getFooterView(position, convertView, parent);
}
return getDataRow(position, convertView, parent);
};
/** A subclass should override this method to supply the data row.
*
* #param position
* #param convertView
* #param parent
* #return */
public abstract View getDataRow(int position, View convertView, ViewGroup parent);
/** returns a View to be displayed in the last row.
*
* #param position
* #param convertView
* #param parent
* #return */
public View getFooterView(int position, View convertView, ViewGroup parent) {
if (position >= mServerListSize && mServerListSize > 0) {
// the ListView has reached the last row
TextView tvLastRow = new TextView(mContext);
tvLastRow.setHint("Reached the last row.");
tvLastRow.setGravity(Gravity.CENTER);
return tvLastRow;
} else {
TextView tvLastRow = new TextView(mContext);
tvLastRow.setHint("Loading...\n position: " + position);
tvLastRow.setGravity(Gravity.CENTER);
return tvLastRow;
}
}
// Defines the process for actually loading more data based on page
public abstract void onLoadMore(int virtualPosition);
#Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
for (int i = -mVisibleThreshold; i < visibleItemCount + mVisibleThreshold; i++) {
int virtualPosition = firstVisibleItem
- EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET + i;
onLoadMore(virtualPosition);
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
EndlessScrollAdapter.java
package com.example.endlessscrollinbothdirections;
import java.util.Map;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class EndlessScrollAdapter extends EndlessScrollBaseAdapter<Integer> {
public EndlessScrollAdapter(Activity activity, Map<Integer, Integer> list) {
super(activity, list);
}
#Override
public View getDataRow(int position, View convertView, ViewGroup parent) {
TextView TextView;
if (convertView == null) {
TextView = new TextView(mContext);
} else {
TextView = (TextView) convertView;
}
TextView.setText("virtualPosition: "
+ (position - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET) + "\n"
+ "row data: "
+ mItems.get(position - EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET));
return TextView;
}
#Override
public void onLoadMore(int virtualPosition) {
// here you might launch an AsyncTask instead
if (!mItems.containsKey(virtualPosition)) {
mItems.put(virtualPosition, virtualPosition);
notifyDataSetChanged();
}
}
}
MainActivity.java
package com.example.endlessscrollinbothdirections;
import java.util.HashMap;
import java.util.Map;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ListView;
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.lvItems);
Map<Integer, Integer> items = new HashMap<Integer, Integer>();
EndlessScrollAdapter endlessScrollAdapter = new EndlessScrollAdapter(this, items);
listView.setAdapter(endlessScrollAdapter);
listView.setSelection(EndlessScrollBaseAdapter.VIRTUAL_MIDDLE_OFFSET);
listView.setOnScrollListener(endlessScrollAdapter);
}
}
activity_main.xml
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/lvItems"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
I am displaying some rows in my ListView and want to change only one of the row, by seeing if any of the date in the list matches today's date.
My partial code is:
DateFormat df = new SimpleDateFormat("EEEEE, LLLL d", Locale.US);
String[] suspendedDates = {
"Tuesday, January 1",
"Wednesday, April 16",
"Monday, October 6",
"Wednesday, December 25"
};
lvDisplay = (ListView) findViewById(R.id.lvDisp);
for (int i = 0; i < suspendedDates.length; i ++) {
sDate = suspendedDates[i];
sReason = datesReason[i];
if (Arrays.asList(suspendedDates).contains(df.format(Calendar.getInstance(Locale.US).getTime()))) {
inIconShow = R.drawable.caliconpressed; //if today matches display a different drawable
contents.add(new SetRows(inIconShow, sDate, sReason));
}
if (!Arrays.asList(suspendedDates).contains(df.format(Calendar.getInstance(Locale.US).getTime()))) {
inIconShow = R.drawable.calicon; //if today doesn't match the array display the default drawable
contents.add(new SetRows(inIconShow, sDate, sReason));
}
}
// Now set your adapter.
adapter = new SetRowsCustomAdapter(MainActivity.this, R.layout.listdates, contents);
lvDisplay.setAdapter(adapter);
SetRowsCustomAdapter class:
import java.util.ArrayList;
import android.app.Activity;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class SetRowsCustomAdapter extends ArrayAdapter<SetRows> {
Context context;
int layoutResourceId;
ArrayList<SetRows> data=new ArrayList<SetRows>();
public SetRowsCustomAdapter(Context context, int layoutResourceId, ArrayList<SetRows> data) {
super(context, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.context = context;
this.data = data;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ImageHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ImageHolder();
holder.txtTitle = (TextView)row.findViewById(R.id.tvDateVal);
//holder.txtTitle.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/robm.ttf"));
holder.imgIcon = (ImageView)row.findViewById(R.id.ivIcon0);
holder.txtID = (TextView)row.findViewById(R.id.tvReasonVal);
//holder.txtID.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/robm.ttf"));
row.setTag(holder);
}
else
{
holder = (ImageHolder)row.getTag();
}
SetRows myImage = data.get(position);
holder.txtTitle.setText(myImage.name);
holder.txtID.setText(myImage.id);
int outImage=myImage.image;
holder.imgIcon.setImageResource(outImage);
return row;
}
static class ImageHolder
{
ImageView imgIcon;
TextView txtTitle;
TextView txtID;
}
}
So the 4th row should have a different icon and the other 3 should have default icon. What is happening is if the date matches, every row has the different icon, otherwise every row has the default icon.
How do I fix it?
if you want change the image you can do in getView method like bellow code:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
ImageHolder holder = null;
if(row == null)
{
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ImageHolder();
holder.txtTitle = (TextView)row.findViewById(R.id.tvDateVal);
//holder.txtTitle.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/robm.ttf"));
holder.imgIcon = (ImageView)row.findViewById(R.id.ivIcon0);
holder.txtID = (TextView)row.findViewById(R.id.tvReasonVal);
//holder.txtID.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/robm.ttf"));
row.setTag(holder);
}
else
{
holder = (ImageHolder)row.getTag();
}
SetRows myImage = data.get(position);
holder.txtTitle.setText(myImage.name);
holder.txtID.setText(myImage.id);
int outImage=myImage.image;
if (data.getValue)
holder.imgIcon.setImageResource(deferentIcon);
else
holder.imgIcon.setImageResource(defaultIcon);
return row;
}
and if you want change multi row icons you can send one list of your row and check in that, and for refresh you list use adapter.notifyDataSetChanged()
Edit
for your situation you can add on boolean value in your DS and if date equal set true otherwise set else that and in if statement check that
Use viewHolder in adapter then use notifyDataSetChanged() in adapter;
I already used and it will help.
I have a custom list view adapter populated through an asynctask, I'm calling notifydatasetchanged in the onprogress function, and getCount() returns 10, yet my list never shows, Ive set a breakpoint and determined that getView() simply never is called. any ideas? Ive tried for hours and Im just stumped. Ive done the exactly same thing in another activity except that one used viewholders, this one only holds text based data so I didn't bother.
Adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if(row == null) {
row = inflater.inflate(R.layout.podcastepisode, null);
}
PodcastItem item = items.get(position);
TextView episodeTitle = (TextView)row.findViewById(R.id.episodeTitle);
TextView episodeDate = (TextView)row.findViewById(R.id.episodeDate);
episodeTitle.setText(item.title);
episodeDate.setText(API.FormatPodcastDate(item.date));
return row;
}
My task:
protected void onProgressUpdate(PodcastItem... progress) {
AddPodcastActivity.episodes.add(progress[0]);
AddPodcastActivity.adapter.notifyDataSetChanged();
}
I'd recommend moving your list adapter from inside the Activity file to it's own file, and using something like this:
import java.util.ArrayList;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
public class EpisodeArrayAdapter extends BaseAdapter {
public EpisodeArrayAdapter(Context context) {
mContext = context;
items = new ArrayList<PodcastItem>();
}
private Context mContext;
private ArrayList<PodcastItem> items;
public void add(PodcastItem item) {
items.add(item);
notifyDataSetChanged();
}
public void remove(int index) {
items.remove(index);
notifyDataSetChanged();
}
public void clear() {
items.clear();
notifyDataSetChanged();
}
#Override
public int getCount() { return items.size(); }
#Override
public Object getItem(int position) { return items.get(position); }
#Override
public long getItemId(int position) { return position; }
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View row = convertView;
if(row == null) row = LayoutInflater.from(mContext).inflate(R.layout.podcastepisode, null);
PodcastItem item = items.get(position);
TextView episodeTitle = (TextView)row.findViewById(R.id.episodeTitle);
TextView episodeDate = (TextView)row.findViewById(R.id.episodeDate);
episodeTitle.setText(item.title);
episodeDate.setText(API.FormatPodcastDate(item.date));
return row;
}
}
This is the type of code we use for all the list adapters in Boid :) Also, notice that the add/remove/clear functions call notifyDataSetChanged(), which makes it so you don't have to call it yourself when adding items.
When you initialize it, you would just use:
EpisodeArrayAdapter adapter = new EpisodeArrayAdapter(this);
listView.setAdapter(adapter);
Adding items with the add() function will cause the list to update immediately. Make sure you call setAdapter for the list view that's using the adapter, otherwise there won't be any connection and nothing will show up in the list (didn't see a call to this in your code).