Change ListView background - strange behaviour - java

I have a problem with changing the background of a view in a ListView.
What I need:
Change the background image of a row onClick()
What actually happens:
The background gets changed (selected) after pressing e.g. the first entry. But after scrolling down the 8th entry is selected too.
Scroll back to the top the first isn't selected anymore. The second entry is selected now.
Continue scrolling and it continues jumping...
What i'm dong in the Code:
I have channels, and onClick() I toggle an attribute of channel boolean selected
and then I change the background.
I'm doing this only onClick() thats why I don't get why it's actuelly happening on other entries too.
One thing I notices is: It seems to be only the "drawing"-part because the item which get selected "by it self" has still the selected value on false
I think it seems to have something to do with the reuse of the views in the custom ListAdapters getView(...)
Code of onClick() in ListActivity:
#Override
protected ViewHolder createHolder(View v) {
// createHolder will be called only as long, as the ListView is not
// filled
TextView title = (TextView) v
.findViewById(R.id.tv_title_channel_list_adapter);
TextView content = (TextView) v
.findViewById(R.id.tv_content_channel_list_adapter);
ImageView icon = (ImageView) v
.findViewById(R.id.icon_channel_list_adapter);
if (title == null || content == null || icon == null) {
Log.e("ERROR on findViewById",
"Couldn't find Title, Content or Icon");
}
ViewHolder mvh = new MyViewHolder(title, content, icon);
// We make the views become clickable
// so, it is not necessary to use the android:clickable attribute in
// XML
v.setOnClickListener(new ChannelListAdapter.OnClickListener(mvh) {
public void onClick(View v, ViewHolder viewHolder) {
// we toggle the enabled state and also switch the the
// background
MyViewHolder mvh = (MyViewHolder) viewHolder;
Channel ch = (Channel) mvh.data;
ch.setSelected(!ch.getSelected()); // toggle
if (ch.getSelected()) {
v.setBackgroundResource(R.drawable.row_blue_selected);
} else {
v.setBackgroundResource(R.drawable.row_blue);
}
// TESTING
Log.d("onClick() Channel", "onClick() Channel: "
+ ch.getTitle() + " selected: " + ch.getSelected());
}
});
return mvh;
}
Code of getView(...):
#Override
public View getView(int position, View view, ViewGroup parent) {
ViewHolder holder;
// When view is not null, we can reuse it directly, there is no need
// to reinflate it.
// We only inflate a new View when the view supplied by ListView is
// null.
if (view == null) {
view = mInflater.inflate(mViewId, null);
// call own implementation
holder = createHolder(view);
// TEST
// we set the holder as tag
view.setTag(holder);
} else {
// get holder back...much faster than inflate
holder = (ViewHolder) view.getTag();
}
// we must update the object's reference
holder.data = getItem(position);
// <EDIT SOLUTION>
if(getItem(position).get_id() == channelList.get(position).get_id()){
if(getItem(position).getSelected())
{
view.setBackgroundResource(R.drawable.row_blue_selected);
}
else{
view.setBackgroundResource(R.drawable.row_blue);
}
}
// </EDIT SOLUTION>
// call the own implementation
bindHolder(holder);
return view;
}
I really would appreciate any idea how to solve this! :)
If more information is needed please tell me.
Thanks in advance!

Let me show you the code that I use for every ListView and properly controlling the click event for changing the background and doing anything further
public class Offices extends Activity {
private ListView listView;
/* selectedListItem will contain the number of items to be selected.
* Your list item OnOlickListener will simply change this variable
* to the position of the clicked item. The Adapter will do the rest
* because you need to refresh the ListView.
*/
private int selectedListItem = -1;
private Handler mHandler = new Handler();
private Vector<String> data;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.officeslayout);
data = new Vector<String>();
// Add data as per your requirement
data.add("one");
data.add("two");
data.add("three");
data.add("four");
data.add("Five");
data.add("Six");
data.add("Seven");
data.add("Eight");
data.add("Nine");
data.add("Ten");
listView = (ListView)findViewById(R.id.ListView01);
listView.setDivider(null);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
selectedListItem = position;
((EfficientAdapter)listView.getAdapter()).notifyDataSetChanged();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
// call any new activity here or do any thing you want here
}
}, 200L);
}
});
listView.setAdapter(new EfficientAdapter(getApplicationContext()));
}
private class EfficientAdapter extends BaseAdapter {
private LayoutInflater mInflater;
public EfficientAdapter(Context context) {
mInflater = LayoutInflater.from(context);
}
public int getCount() {
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null || convertView.getTag() == null) {
convertView = mInflater.inflate(R.layout.officeslistitemlayout, null);
holder = new ViewHolder();
holder.backgroundView = (ImageView) convertView
.findViewById(R.id.OfficesBackground);
holder.officesTitle = (TextView) convertView
.findViewById(R.id.OfficesName);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if(position == selectedListItem) {
holder.backgroundView.setBackgroundResource(R.drawable.and_gray_bg_listing_selected);
} else {
holder.backgroundView.setBackgroundResource(R.drawable.and_gray_bg_listing);
}
holder.officesTitle.setText(data.get(position));
return convertView;
}
}
static class ViewHolder {
TextView officesTitle;
ImageView backgroundView;
}
}
officeslistitemlayout.xml file will be like following add drawable and design it according to you put the following code in RelativeLayout
<ImageView android:id="#+id/OfficesBackground" android:layout_width="fill_parent"
android:layout_height="45dip"
android:layout_alignParentTop="true"
android:background="#drawable/and_gray_bg_listing"
android:scaleType="fitXY"
></ImageView>
<TextView android:id="#+id/OfficesName" android:layout_width="wrap_content"
android:text="Offices Name"
android:textColor="#000000" android:textStyle="bold"
android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_marginLeft="5dip"
></TextView>
Hope it will help :)

Related

Change TextView text to Normal after the object has been pressed

I currently have a ListView which uses a CustomAdapter to display the information from my Firebase Database. Which looks like the following:
Upon creation I want the text in the green boxes (The ListView Items) to be bold. Once the user presses on that ListView item I want the text to go to Normal, unbolded.
I want it to work similar to an email. When you get a new email the title is bold and once that email is opened and you go back to your inbox the text is the Normal, unbolded.
The following is all my relevant code:
MyJobsFragment, SelectItem
// Press the object and display the information and sign the job of with signature pad
jobListViewMyAcJobs.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
ActiveJobDetailsFragment activeJobDetailsFragment = new ActiveJobDetailsFragment();
Bundle bundle = new Bundle();
bundle.putSerializable("Job", adapterActiveJobs.mData.get(position));
bundle.putSerializable("JobId", adapterActiveJobs.mDataKeys.get(position));
activeJobDetailsFragment.setArguments(bundle);
getFragmentManager().beginTransaction().replace(R.id.content, activeJobDetailsFragment).addToBackStack(host.getCurrentTabTag()).commit();
}
});
MyCustomAdapter
public class MyCustomAdapter extends BaseAdapter
{
private ArrayList<JobInformation> mData = new ArrayList<>();
private ArrayList<JobInformation> mDataOrig = new ArrayList<>();
private ArrayList<String> mDataKeys = new ArrayList<>();
private LayoutInflater mInflater;
... Removed Code ...
#Override
public View getView(final int position, View convertView, ViewGroup parent)
{
// Bid on holder
MyJobsFragment.MyCustomAdapter.GroupViewHolderBidOn holderBidOn;
// Accepted holder
final MyJobsFragment.MyCustomAdapter.GroupViewHolderAccepted holderAccepted;
// Completed holder
MyJobsFragment.MyCustomAdapter.GroupViewHolderCompleted holderCompleted;
if (convertView == null)
{
// Bid on
if (host.getCurrentTab() == 0)
{
convertView = mInflater.inflate(R.layout.job_info_bid_on, null);
holderBidOn = new MyJobsFragment.MyCustomAdapter.GroupViewHolderBidOn();
holderBidOn.textViewJobName = convertView.findViewById(R.id.textName);
holderBidOn.textViewJobDescription = convertView.findViewById(R.id.textDesc);
holderBidOn.textViewJobName.setText(mData.get(position).getAdvertName());
holderBidOn.textViewJobDescription.setText(mData.get(position).getAdvertDescription());
convertView.setTag(holderBidOn);
}
// Accepted
else if (host.getCurrentTab() == 1)
{
convertView = mInflater.inflate(R.layout.job_info_accepted, null);
holderAccepted = new MyJobsFragment.MyCustomAdapter.GroupViewHolderAccepted();
holderAccepted.textViewJobName = convertView.findViewById(R.id.textName);
holderAccepted.textViewDescription = convertView.findViewById(R.id.textDesc);
holderAccepted.textViewJobName.setText(mData.get(position).getAdvertName());
if(text != null)
{
text.setTypeface(null, Typeface.BOLD);
}
holderAccepted.textViewDescription.setText(mData.get(position).getAdvertDescription());
// TODO - Was going to add the the users bid into this here, however it's difficult as the bid isnt stored in the jobs table
// TODO - I tried to add it in, looped through the bids table and found the bids with the mDataKeys. But it always displayed the last value.
convertView.setTag(holderAccepted);
}
// Completed
else if (host.getCurrentTab() == 2)
{
convertView = mInflater.inflate(R.layout.job_info_list_completed, null);
holderCompleted = new MyJobsFragment.MyCustomAdapter.GroupViewHolderCompleted();
holderCompleted.textViewJobName = convertView.findViewById(R.id.textName);
holderCompleted.textViewJobName.setText(mData.get(position).getAdvertName());
convertView.setTag(holderCompleted);
}
} else
{
if (host.getCurrentTab() == 0)
{
holderBidOn = (MyJobsFragment.MyCustomAdapter.GroupViewHolderBidOn) convertView.getTag();
} else if (host.getCurrentTab() == 1)
{
holderAccepted = (MyJobsFragment.MyCustomAdapter.GroupViewHolderAccepted) convertView.getTag();
} else if (host.getCurrentTab() == 2)
{
holderCompleted = (MyJobsFragment.MyCustomAdapter.GroupViewHolderCompleted) convertView.getTag();
}
}
return convertView;
}
public class GroupViewHolderBidOn
{
public TextView textViewJobName;
public TextView textViewJobDescription;
}
public class GroupViewHolderAccepted
{
public TextView textViewJobName;
public TextView textViewDescription;
}
public class GroupViewHolderCompleted
{
public TextView textViewJobName;
}
}
Well there multiple ways of achieving that. I would suggest you to add a field in your JobInformation class, something like
public class JobInformation{
.
.
.
.
. // other fields
private boolean isSelected;
public boolean isSelected() {
return isSelected;
}
public void setSelected(boolean selected) {
isSelected = selected;
}
.
.
. // Other getters/setters
}
Now you need to set this field when you click an item, in your onItemClick function do this
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
ActiveJobDetailsFragment activeJobDetailsFragment = new ActiveJobDetailsFragment();
Bundle bundle = new Bundle();
adapterActiveJobs.mData.get(position).setSelected(true); // add this line in your code
bundle.putSerializable("Job", adapterActiveJobs.mData.get(position));
bundle.putSerializable("JobId", adapterActiveJobs.mDataKeys.get(position));
activeJobDetailsFragment.setArguments(bundle);
getFragmentManager().beginTransaction().replace(R.id.content, activeJobDetailsFragment).addToBackStack(host.getCurrentTabTag()).commit();
}
finally in your getView method in your custom adapter, check for isSelected field and style your textview accordingly, add this in your getView method.
if(mData.get(position).isSelected()){
// set your textview typeface to normal
}
else{
// set your texview typeface to bold.
}
and you would need to call adapter.notifyDataSetChanged() whenever you update selected variable so that your getView is called.

Handling onClick with efficient ListView adapter

Here's my getView function in a custom class extending ArrayAdapter.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Thing p = getItem(position);
Thing.ThingStatus thingStatus = p.getStatus();
int thingStatusIcon; // change to thingStatusResource
switch (thingStatus) {
case A:
thingStatusIcon = ICON_A;
break;
case B:
thingStatusIcon = ICON_B;
break;
default:
thingStatusIcon = ICON_C;
break;
}
// Check if an existing view is being reused, otherwise inflate the view
ThingRowHolder viewHolder; // view lookup cache stored in tag
if (convertView == null) {
// If there's no view to re-use, inflate a brand new view for row
viewHolder = new ThingRowHolder();
LayoutInflater inflater = LayoutInflater.from(getContext());
convertView = inflater.inflate(R.layout.thing_list_item, parent, false);
// put these on the top like the colors
viewHolder.thingIcon = (ImageView) convertView.findViewById(R.id.thing_icon);
viewHolder.thingId = (TextView) convertView.findViewById(R.id.thing_id_item);
viewHolder.thingStatus = (TextView) convertView.findViewById(R.id.thing_status_item);
// Cache the viewHolder object inside the fresh view
convertView.setTag(viewHolder);
} else {
// View is being recycled, retrieve the viewHolder object from tag
viewHolder = (ThingRowHolder) convertView.getTag();
}
viewHolder.thingId.setText(p.getLpId());
viewHolder.thingStatus.setText(thingStatus.toString());
viewHolder.thingIcon.setImageResource(thingStatusIcon);
viewHolder.position = position;
return convertView;
}
I'm trying to add an onClick event listener for each row in my ListView. I tried setting the listener on convertView both inside the if statement and outside the else statement. I got mixed results. Sometimes the onClick wouldn't fire at all. Other times it would report the wrong position. I've scoured SO for examples of this and I'm surprised such a common functionality isn't well documented and/or not working in my case.
Any help would be much appreciated!
edit:
private class ThingRowHolder {
ImageView thingIcon;
TextView thingId;
TextView thingStatus;
}
edit 2:
private void refreshList() {
ArrayList<Thing> things = mThingContainer.getThings();
Collections.sort(things);
mThingListAdapter.refreshThings(things);
}
edit 3:
mThingListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ThingListAdapter.ThingRowHolder holder =
(ThingListAdapter.ThingRowHolder) view.getTag();
Thing p = mThingContainer.getThings().get(holder.position);
}
});
Set position as tag to your view,
convertview.setTag(R.id.thing_icon, position);
Now in your onClick(View v),
int pos = (int)v.getTag(R.id.thing_icon);
Thing p = getItem(pos);
You can now use p as desired.
Edit 1 : Updating data in adapter
In your adapter, add the following method :
public void updateData(List<Thing> data) {
if (data != null) {
mData.clear();
mData.addAll(data);
notifyDataSetChanged();
}
}
Now just call updateData method of adapter whenever you need to update the data.
Use these inside your getView method
If you want long click
convertView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View view) {}}
if you want normal click
convertView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {}}

Search line for customArrayAdapter - Android

I've been trying to solve this one but couldn't find any answer here.
what i'm trying to do is create an EditText search for custom arrayList, using ArrayAdapter.
All is going well until I actually search for an Object (named Product in this project).
when I search for one, meaning i input chars into the EditText the list goes blank and I cannot see any Items.
This is my code:
SearchActivity , receiving the ArrayList from the mainactivity :
public class SearchActivity extends Activity {
EditText editSearch;
ProductArrayAdapter productsAdapter;
ListView products;
static ArrayList<Product> viewList;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
viewList = new ArrayList<Product>(MainActivity.listToBeSent);
Toast.makeText(getBaseContext(), viewList.get(1).getName(), Toast.LENGTH_LONG).show();
productsAdapter = new ProductArrayAdapter(this,
R.layout.layout_product, viewList);
products = (ListView) findViewById(R.id.listProducts);
products.setAdapter(productsAdapter);
editSearch = (EditText)findViewById(R.id.searchLine);
editSearch.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String charsToSearch = editSearch.getText().toString().toLowerCase(Locale.getDefault());
productsAdapter.filter(charsToSearch);
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
#Override
public void afterTextChanged(Editable s) {
String charsToSearch = editSearch.getText().toString().toLowerCase(Locale.getDefault());
productsAdapter.filter(charsToSearch);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.search, 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();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
ProductArrayAdapter which has the filter() method inside.
public class ProductArrayAdapter extends ArrayAdapter<Product> {
ArrayList<Product> products;
Context context;
int resource;
public ProductArrayAdapter(Context context, int resource,
ArrayList<Product> products) {
super(context, resource, products);
this.context=context;
this.resource=resource;
this.products=products;
}
public void filter(String charText) {
charText = charText.toLowerCase(Locale.getDefault());
this.products.clear();
if (charText.length() == 0) {
this.products.addAll(SearchActivity.viewList);
} else {
for (Product singleProduct : SearchActivity.viewList) {
if (singleProduct.getName().toLowerCase(Locale.getDefault())
.contains(charText)) {
products.add(singleProduct);
}
}
}
notifyDataSetChanged();
}
static class ViewContainer {
public TextView txtName;
public TextView txtDescription;
public TextView txtPrice;
public ImageView imgProduct;
public ImageView imgOnSale;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewContainer viewContainer;
View rowView = convertView;
// means that if it is the first time and we didn't yet inflate the
// view, so inflate it now. rowView gets the already built or non-exist
// convertView.
if (rowView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
rowView = inflater.inflate(resource, null);
viewContainer = new ViewContainer();
/*viewContainer.textName = (TextView) rowView
.findViewById(this.textViewResource);*/
viewContainer.txtName = (TextView) rowView
.findViewById(R.id.txtName);
viewContainer.txtDescription = (TextView) rowView
.findViewById(R.id.txtDescription);
viewContainer.txtPrice = (TextView) rowView
.findViewById(R.id.txtPrice);
viewContainer.imgProduct = (ImageView) rowView
.findViewById(R.id.productPic);
viewContainer.imgOnSale = (ImageView) rowView
.findViewById(R.id.onSaleImage);
// adding tag to each rowView , tag can be Object therefore
// viewContainer = Object.
rowView.setTag(viewContainer);
} else {
viewContainer = (ViewContainer) (rowView.getTag());
}
Toast.makeText(getContext(), products.get(1).getCategory(), Toast.LENGTH_LONG).show();
Toast.makeText(getContext(), products.get(2).getCategory(), Toast.LENGTH_LONG).show();
viewContainer.txtName.setText(products.get(position).getName());
viewContainer.txtDescription.setText(products.get(position).getDescription());
viewContainer.txtPrice.setText("Price: " + (products.get(position).getPrice().toString()));
viewContainer.imgProduct.setImageResource(products.get(position).getImage());
viewContainer.imgOnSale.setImageResource(R.drawable.logo_icon);
return rowView;
}
I think the main problem is with the viewContainer part.
Appreciate your help !
Thank you Jay, just edited my code, now it does filter some items, but it seems like it doesn't
filter by the right chars, for example , when I search the letter 'r' it does get 'r' as the charSequence but it shows only the first item , and not the correct one .
here are the edited relevant lines :
on the textChangeListener I entered :
#Override
public void afterTextChanged(Editable s) {
String charsToSearch = editSearch.getText().toString().toLowerCase();
productsAdapter.getFilter().filter(charsToSearch);
}
and on the ProductArrayAdapter I changed the getView() method to :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewContainer viewContainer;
//View rowView = convertView;
// means that if it is the first time and we didn't yet inflate the
// view, so inflate it now. rowView gets the already built or non-exist
// convertView.
if (convertView == null) {
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
convertView = inflater.inflate(resource, parent, false);
viewContainer = new ViewContainer();
viewContainer.txtName = (TextView) convertView
.findViewById(R.id.txtName);
viewContainer.txtDescription = (TextView) convertView
.findViewById(R.id.txtDescription);
viewContainer.txtPrice = (TextView) convertView
.findViewById(R.id.txtPrice);
viewContainer.imgProduct = (ImageView) convertView
.findViewById(R.id.productPic);
viewContainer.imgOnSale = (ImageView) convertView
.findViewById(R.id.onSaleImage);
// adding tag to each rowView , tag can be Object therefore
// viewContainer = Object.
convertView.setTag(viewContainer);
} else {
viewContainer = (ViewContainer) (convertView.getTag());
}
viewContainer.txtName.setText(products.get(position).getName());
viewContainer.txtDescription.setText(products.get(position).getDescription());
viewContainer.txtPrice.setText("Price: " + (products.get(position).getPrice().toString()));
viewContainer.imgProduct.setImageResource(products.get(position).getImage());
viewContainer.imgOnSale.setImageResource(R.drawable.logo_icon);
return convertView;
}
Any Ideas?
Remove your filter method. That is not the correct way to handle filtering with an adapter. The ArrayAdapter already supports a basic filtering mechanism. Simply do:
productsAdapter.getFilter.filter(charsToSearch);
For each product stored in the adapter, it'll do a:
singleProduct.toString().toLowerCase().startsWith(charsToSearch);
If the startsWith() logic works for you, a quick working solution would be to override the toString() method for your Product class and have it return getName(). Otherwise, there are really only two solutions available if you want a more custom solution for the filtering logic:
Write your own adapter from scratch using BaseAdapter and have it implement the Filterable interface. While a very basic implementation isn't too bad, it can be quite daunting if you never did it before.
Utilize an existing 3rd party library which allows you to add your own filtering logic.
Also note, when working with the ArrayAdapter it's very dangerous to keep your own copy of the list outside of what's constructed with the super. Especially when filtering is concerned. There's no guarantee that the list used to construct the adapter is the same one you are referencing externally. For further reading, go here.
For your getView() method, make sure you use getItem(position) instead of directly referencing products. Placing Toasts inside there is also not a good idea. When displaying your list, you will end up seeing a ton of Toasts pop up all at once. If you need debuging statements, use Log instead. Also, you need to adjust the following lines:
rowView = inflater.inflate(resource, null);
viewContainer = new ViewContainer();
To this instead:
viewContainer = inflater.inflate(resouce, parent, false);
You don't need that rowView variable at all. Just remove completely from the method and replace with viewContainer. Otherwise, your getView() method looks fine.

How can I use a view from different class?

I've searched a lot this but I really did not find what I need exactly.
What I want is :
I have a listview and load it on my main class. I load it like this:
ArrayAdapter<String> adapter = new ArrayAdapter<String>(Main.this,
R.layout.myrow,R.id.text );
if (friends != null) {
for (ParseObject friend : friends) {
adapter.add((String) friend.get("name"));
}
}
setListAdapter(adapter);
and myrow layout xml is here:
< RelativeLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center" >
<ProgressBar
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/my_prog"
></ProgressBar>
<TextView
android:id="#+id/text"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="25sp" >
</TextView>
</RelativeLayout >
You can see I have progress bar on textview so I need to reach it and set it's visible. I mean sometimes I set it invisible sometimes visible
What I did is:
On my MainActivity on create method the code is here :
ProgressBar my_prog;
my_prog=(ProgressBar)findViewById(R.id.my_prog);
my_prog.setVisibility(View.INVISIBLE);
The error is:
07-16 13:35:39.219: E/AndroidRuntime(29096): java.lang.RuntimeException: Unable to start activity ComponentInfo{....MainActivity}: java.lang.NullPointerException
I think I cant reach my_prog on my main activity but I need it.
How can I do that.
thanks in adnvace...
You need to implement a custom Adapter to do this. I have written this ExampleAdapter to show you how it works, I commented all the important parts:
public class ExampleAdapter extends BaseAdapter {
private final LayoutInflater inflater;
private final List<ParseObject> objects;
private final boolean[] activated;
public ExampleAdapter(Context context, List<ParseObject> objects) {
this.inflater = LayoutInflater.from(context);
this.objects = objects;
this.activated = new boolean[objects.size()];
}
public void showProgressBar(int position, boolean visible) {
this.activated[position] = visible;
notifyDataSetChanged();
}
#Override
public int getCount() {
return this.objects.size();
}
#Override
public ParseObject getItem(int position) {
return this.objects.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// If the convertView is null, we need to inflate a new one
if(convertView == null) {
// We inflate the view with your layout
convertView = inflater.inflate(R.layout.myrow, parent, false);
// Here we create a view holder object which keeps a
// reference to the Views in this row so we have to
// perform the expensive findViewById() only once
ViewHolder holder = new ViewHolder();
holder.text = (TextView) convertView.findViewById(R.id.text);
holder.my_prog = (ProgressBar) convertView.findViewById(R.id.my_prog);
// The view holder is set as tag to the view so we can access it later
convertView.setTag(holder);
}
// We retrieve the ParseObject for the current position
ParseObject parseObject = getItem(position);
// And get the view holder from the View
ViewHolder holder = (ViewHolder) convertView.getTag();
// We read the data we need from the ParseObject
String name = parseObject.get("name");
// And here is the visibility logic
int progressBarVisibility = this.activated[position] ? View.VISIBLE : View.GONE;
int textViewVisibility = this.activated[position] ? View.GONE : View.VISIBLE;
// Now we set the data to the Views through the view holder
holder.text.setText(name);
holder.text.setVisibility(textViewVisibility);
holder.my_prog.setVisibility(progressBarVisibility);
return convertView;
}
// This is our view holder class. It keeps a reference to the Views
// inside each row so we have to perform the expensive
// findViewById() only once
private class ViewHolder {
public TextView text;
public ProgressBar my_prog;
}
}
You can use the ExampleAdapter like this:
if(friends != null) {
ExampleAdapter adapter = new ExampleAdapter(Main.this, friends);
setListAdapter(adapter);
}
If you want to show a ProgressBar at a specific position you just do this:
// Shows the ProgressBar in the first row
adapter.showProgressBar(0, true)

Listview selects mutliple items when clicked

I'm trying to make a task manager, and I only have one problem. I have a listview that gets inflated. All the elements in the listview are correct. The problem is that when I select an item, the listview will select another item away. I've heard listviews repopulate the list as it scrolls down to save memory. I think this may be some sort of problem. Here is a picture of the problem.
If i had more apps loaded, then it would continue to select multiple at once.
Here is the code of my adapter and activity and XML associated
public class TaskAdapter extends BaseAdapter{
private Context mContext;
private List<TaskInfo> mListAppInfo;
private PackageManager mPack;
public TaskAdapter(Context c, List<TaskInfo> list, PackageManager pack) {
mContext = c;
mListAppInfo = list;
mPack = pack;
}
#Override
public int getCount() {
return mListAppInfo.size();
}
#Override
public Object getItem(int position) {
return mListAppInfo.get(position);
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
TaskInfo entry = mListAppInfo.get(position);
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
//System.out.println("Setting LayoutInflater in TaskAdapter " +mContext +" " +R.layout.taskinfo +" " +R.id.tmbox);
convertView = inflater.inflate(R.layout.taskinfo,null);
}
ImageView ivIcon = (ImageView)convertView.findViewById(R.id.tmImage);
ivIcon.setImageDrawable(entry.getIcon());
TextView tvName = (TextView)convertView.findViewById(R.id.tmbox);
tvName.setText(entry.getName());
convertView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
final CheckBox checkBox = (CheckBox)v.findViewById(R.id.tmbox);
if(v.isSelected())
{
System.out.println("Listview not selected ");
//CK.get(arg2).setChecked(false);
checkBox.setChecked(false);
v.setSelected(false);
}
else
{
System.out.println("Listview selected ");
//CK.get(arg2).setChecked(true);
checkBox.setChecked(true);
v.setSelected(true);
}
}
});
return convertView;
public class TaskManager extends Activity implements Runnable
{
private ProgressDialog pd;
private TextView ram;
private String s;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.taskpage);
setTitleColor(Color.YELLOW);
Thread thread = new Thread(this);
thread.start();
}
#Override
public void run()
{
//System.out.println("In Taskmanager Run() Thread");
final PackageManager pm = getPackageManager();
final ListView box = (ListView) findViewById(R.id.cBoxSpace);
final List<TaskInfo> CK = populate(box, pm);
runOnUiThread(new Runnable()
{
#Override
public void run()
{
ram.setText(s);
box.setAdapter(new TaskAdapter(TaskManager.this, CK, pm));
//System.out.println("In Taskmanager runnable Run()");
endChecked(CK);
}
});
handler.sendEmptyMessage(0);
}
Taskinfo.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal">
<ImageView
android:id="#+id/tmImage"
android:layout_width="48dp"
android:layout_height="48dp"
android:scaleType="centerCrop"
android:adjustViewBounds="false"
android:focusable="false" />
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/tmbox"
android:lines="2"/>
</LinearLayout>
Taskpage.xml
<?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">
<ListView
android:id="#+id/cBoxSpace"
android:layout_width="wrap_content"
android:layout_height="400dp"
android:orientation="vertical"/>
<TextView
android:id="#+id/RAM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="18sp" />
<Button
android:id="#+id/endButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="End Selected Tasks" />
</LinearLayout>
Any ideas for what reason mutliple items are selected with a single click would be GREATLY appreciated. I've been messing around with different implementations and listeners and listadapters but to no avail.
I think the point is you only save checking state in the view(v.setSelected).
And you reuse these view, so its checkbox is always not change its state.
You can create a state array to save every checking state of every TaskInfo, and check this array when you create a view.
for example
// default is false
ArrayList<Boolean> checkingStates = new ArrayList<Boolean>(mListAppInfo.size());
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
TaskInfo entry = mListAppInfo.get(position);
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
convertView = inflater.inflate(R.layout.taskinfo,null);
}
ImageView ivIcon = (ImageView)convertView.findViewById(R.id.tmImage);
ivIcon.setImageDrawable(entry.getIcon());
TextView tvName = (TextView)convertView.findViewById(R.id.tmbox);
tvName.setText(entry.getName());
final CheckBox checkBox = (CheckBox)v.findViewById(R.id.tmbox);
checkBox.setChecked(checkingStates.get(position));
convertView.setSelected(checkingStates.get(position));
convertView.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
if(v.isSelected())
{
System.out.println("Listview not selected ");
//CK.get(arg2).setChecked(false);
checkBox.setChecked(false);
v.setSelected(false);
checkingStates.get(position) = false;
}
else
{
System.out.println("Listview selected ");
//CK.get(arg2).setChecked(true);
checkBox.setChecked(true);
v.setSelected(true);
checkingStates.get(position) = true;
}
}
});
return convertView;
}
I'm not 100% sure what you are trying to do, but part of your problem might be related to the condition in your onClick method:
if(v.isSelected())
I think you want that to read
if(v.isChecked())
isSelected is inherited from View, and it means something different from isChecked
Also, the whether the CheckBox is checked or not is independent from your data model since it is a recycled view. Your CheckBox should be checked based on entry (I'm assuming your TextInfo class has an isChecked() method that returns a boolean:
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
TaskInfo entry = mListAppInfo.get(position);
if (convertView == null)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
//System.out.println("Setting LayoutInflater in TaskAdapter " +mContext +" " +R.layout.taskinfo +" " +R.id.tmbox);
convertView = inflater.inflate(R.layout.taskinfo,null);
}
ImageView ivIcon = (ImageView)convertView.findViewById(R.id.tmImage);
ivIcon.setImageDrawable(entry.getIcon());
TextView tvName = (TextView)convertView.findViewById(R.id.tmbox);
tvName.setText(entry.getName());
CheckBox checkBox = (CheckBox)v.findViewById(R.id.tmbox);
checkBox.setChecked(entry.isChecked());
}
I don't think you need the View.OnClickListener you are attaching to convertView. You should handle that in the OnItemClickListener attached to the ListView. Assuming your ListView is called listView and TaskInfo instances have setChecked and isChecked methods:
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView parent, View v, int position, long id) {
entry = mListAppInfo.get(position);
entry.setChecked(!entry.isChecked());
}
});
First of all don't set the list checked or unchecked on view position.
because view position means only visible items position in your listview but you would like to set checked or uncheked status on a particular list item.
That's why this problem arises in your code.
You have the need to set the items checked and unchecked on your custom arraylist getter setter like the code i have attached below:
package com.app.adapter;
public class CategoryDynamicAdapter {
public static ArrayList<CategoryBean> categoryList = new ArrayList<CategoryBean>();
Context context;
Typeface typeface;
public static String videoUrl = "" ;
Handler handler;
Runnable runnable;
// constructor
public CategoryDynamicAdapter(Activity a, Context context, Bitmap [] imagelist,ArrayList<CategoryBean> list) {
this.context = context;
this.categoryList = list;
this.a = a;
}
// Baseadapter to the set the data response from web service into listview.
public BaseAdapter mEventAdapter = new BaseAdapter() {
#Override
public int getCount() {
return categoryList.size();
}
#Override
public Object getItem(int position) {
return categoryList.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
class ViewHolder {
TextView title,category,uploadedBy;
ImageView image;
RatingBar video_rating;
Button report_video ,Flag_video;
}
public View getView(final int position, View convertView, final ViewGroup parent) {
ViewHolder vh = null ;
if(convertView == null) {
vh = new ViewHolder();
convertView = LayoutInflater.from(context).inflate (R .layout.custom_category_list_layout,null,false);
vh.title = (TextView) convertView .findViewById (R.id.title);
vh.image = (ImageView) convertView.findViewById(R.id.Imagefield);
convertView.setTag(vh);
}
else
{
vh=(ViewHolder) convertView.getTag();
}
try
{
final CategoryBean Cb = categoryList.get(position);
//pay attention to code below this line i have shown here how to select a listview using arraylist getter setter objects
String checkedStatus = Cb.getCheckedStringStaus();
if(checkdStatus.equal("0")
{
System.out.println("Listview not selected ");
//CK.get(arg2).setChecked(false);
checkBox.setChecked(false);
v.setSelected(false);
}
else ////checkdStatus.equal("1")
{
System.out.println("Listview selected ");
//CK.get(arg2).setChecked(true);
checkBox.setChecked(true);
v.setSelected(true);
}
catch (Exception e)
{
e.printStackTrace();
}

Categories

Resources