listContent.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
for(int i=0;i<showLists.size();i++){
//
TextView v=(TextView)listContent.getChildAt(i).findViewById(R.id.txtDes);
v.setTextColor(Color.BLACK);
}
TextView v=(TextView)listContent.getChildAt(position).findViewById(R.id.txtDes);
v.setTextColor(Color.RED);
Toast.makeText(context,"POS "+showLists.get(position).getDes(),Toast.LENGTH_SHORT).show();
}
});
I have been the problem with get position item of listview. Android just has shown about 12 row on devide's creen, when I click another item on listview (my listview have 30 item ) which shown the error.
And this is error:
"Attempt to invoke virtual method 'android.view.View android.view.View.findViewById(int)' on a null object reference" .
Thanks for read.
listContent.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
for (int i = 0; i < showLists.size(); i++) {
TextView v = (TextView) view.findViewById(R.id.txtDes);
v.setTextColor(Color.BLACK);
}
TextView v = (TextView) view.findViewById(R.id.txtDes);
v.setTextColor(Color.RED);
Toast.makeText(context, "POS " + showLists.get(position).getDes(), Toast.LENGTH_SHORT).show();
}
});
Your question is indeed about Null Pointer Exception, but is harder to identify why this is happening. The problem can be found here:
for(int i=0;i<showLists.size();i++){ <-- this line actually causes the crash
//
the crash is in the next line, at the findViewById
TextView v=(TextView)listContent.getChildAt(i).findViewById(R.id.txtDes);
v.setTextColor(Color.BLACK);
}
Your for has the wrong upper limit because of a mechanism known as recycling, and because of this mechanism your list view will never have the same number of rows as the amount of data that needs to be displayed (read about recycling to understand this). Given this fact, we know for sure that the number of views found in list view (listContent.getChildCount()) will be smaller than showLists.size() and thus making the call listContent.getChildAt(i) to return a NULL value when the index equals listContent.getChildCount() creating the crash.
Now you might be tempted to change showLists.size() with listContent.getChildCount() and see that the app doesn't crash anymore, but if you click a row, then other rows are coloured also as you scroll the list (the recycling is again the problem). To really fix the problem you should save the index of the selected row and call notifyDatasetChanged, so when getView is called in adapter you simply check the current position to be displayed with the selected position. In case of equality you change the color of text to red, otherwise to black. Below, you will find some parts of an example:
int currentPosition = -1;
// Just a basic adapter. The getView method is the key here
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1) {
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
View view = super.getView(position, convertView, parent);
if (position == currentPosition) {
((TextView) view).setTextColor(Color.RED);
} else {
((TextView) view).setTextColor(Color.BLACK);
}
return view;
}
};
// and here is the onItemClick
listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
currentPosition = position;
adapter.notifyDataSetChanged();
}
});
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View viewRow=convertView;
if(viewRow==null){
viewRow=inflater.inflate(layout,parent,false);
viewHolder viewHolder=new viewHolder();
viewHolder.imgIcon = (ImageView) viewRow.findViewById(R.id.imgIcon);
viewHolder.txtDes = (TextView) viewRow.findViewById(R.id.txtDes);
viewRow.setTag(viewHolder);
}
viewHolder holder= (viewHolder) viewRow.getTag();
holder.imgIcon.setImageResource(listMoiNhat.get(position).getIcon());
holder.txtDes.setText(listMoiNhat.get(position).getDes());
if(position==currentpos){
holder.txtDes.setTextColor(Color.RED);
}
else {
holder.txtDes.setTextColor(Color.RED);
}
return viewRow;
}
//and here is create customListMoiNhat object
final customListMoiNhat customListMoiNhat=new customListMoiNhat(context,R.layout.moinhat_customlistview,showLists,currentpos);
customListMoiNhat.notifyDataSetChanged();
listContent.setAdapter(customListMoiNhat);
listContent.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
currentpos=position;
customListMoiNhat.notifyDataSetChanged();
}
});
Related
I'm in the process of making a grocery list app and I wrote the code to where when I click an item, it'll mark it off.
This is my code for that section:
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
TextView text = (TextView) view;
if (!text.getPaint().isStrikeThruText()) {
text.setPaintFlags(text.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}else{
text.setPaintFlags(text.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
}
});
}
It works exactly like i want but when I add another item after an item is marked off, all of the items that are marked off, the marks disappear.
When I add an item, it's like it resets. it doesn't delete any of my items, just the strike_thru part of it. any help would be greatly appreciated! thanks
Your ListView's Adapter contains a method called getView, which is called when a list view item needs to be displayed in an actual View. The Views in your ListView will be discarded if you scroll too far off screen, or invalidate the whole ListView.
My guess is that adding an item is invalidating the ListView.
Your getView method should set the paint flags on the view that it returns. Assuming your list view is displaying a String[], you will also need a boolean[] to hold whether or not an item is complete. You would need to initialize this to all falses, add a completed[i] = !completed[i] at the beginning of your onItemClick. Then you can check competed[i] instead of isStrikeThruText in your if statement, later in that method. Finally, your getView can look like this
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);
}
TextView textView = (TextView) convertView;
textView.setText(items[position]);
if (completed[position]) {
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
} else {
textView.setPaintFlags(textView.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
return textView;
}
I got the following App with Costume adapter showing 2 images and 1 textview for each listview.
I can push/click/press each ListView just fine but i want to being able to recognize the X press aswell and i seem to not being able to get the view name or resource name.
My mainclass with the setOnItemclickListener looks like this
serverListView.setOnItemClickListener(new android.widget.AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
//recieve and check if X image is pressed
}
});
This is the getView method in my Adapter. I tried to recognize the different image clicks in here without any different results.
#Override
public View getView(final int position,final View convertView,final ViewGroup parent) {
View row = convertView;
ServerHolder holder = null;
if(row == null){
LayoutInflater inflater = ((Activity)context).getLayoutInflater();
row = inflater.inflate(layoutResourceId, parent, false);
holder = new ServerHolder();
holder.imgIcon = (ImageView)row.findViewById(R.id.thumbImage);
holder.txtTitle = (TextView)row.findViewById(R.id.name);
holder.removeIcon = (ImageView)row.findViewById(R.id.removeServer);
row.setTag(holder);
}
else{
holder = (ServerHolder)row.getTag();
}
RowServer rs = servers.get(position);
holder.imgIcon.setImageResource(rs.getIcon());
holder.txtTitle.setText(rs.getName());
return row;
}
You probably have to add listeners to the subitems in getView(...). Try setOnClickListener(...) for the views you want to have events attached.
I want to add a second on click to a ListViewItem.
I already created the View (ImageView) and i set the on Click. The function gets called.
But: How can i get the Informations of this ListViewItem? It would be enough to get the Position in the ListView?
The ImageView:
<ImageView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right|center_vertical"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:onClick="favorite"
android:src="#drawable/star" />
The code for my on click function:
public void favorite(View view){
ImageView iView = (ImageView) view;
iView.setImageResource(R.drawable.star_checked);
ViewParent v = iView.getParent();
}
Use an anonymous inner class:
ImageView iView = (ImageView) findViewById(R.id.imageView1);
iView.setOnClickListener(new OnClickListener(){
public void onClick(View v) {
//Your code
}
});
myListView.setOnItemClickListener(new OnItemClickListener() { ![enter image description here][2]
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String value = myListView.getAdapter().getItem(position).toString(); // String value of the clicked item
//Code
}
});
If you want to make bigger applications you should think about better naming your components, 'imageView1' is not very handy. Name you components like 'imageview_main' or 'imageview_customerdetails'.
Subclass OnItemClickListener rather than OnClickListener.
Edit:
Okay I think I understand what you are trying to do now. I would subclass your ListAdapter and override the getView(int position, ...) method like so:
private OnClickListener mImgClickListener = new OnClickListener() {
#Override
public void onClick(View view) {
int position = (Integer) view.getTag();
// do stuff with position knowledge!
}
});
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView != null) {
v = convertView;
} else {
v = newView(int position);
}
v.findViewById(R.id.imageView1).setTag(position);
return v;
}
private View newView(int position) {
View v;
// inflate your view here
View imageView = v.findViewById(R.id.imageView1);
imageView.setOnClickListener(mImgClickListener);
return v;
}
Of course, even better would be to implement the ViewHolder pattern in the getView method to eliminate expensive calls to findViewById.
I believe the View hierarchy will take care of giving priority to the click on the ImageView (rather than the list item as a whole), but I could be wrong.
I am using Jeff Sharkey's SeparatedListAdapter and I would like to set the text color, but I'm not sure how.
To give you some background on his adapter, he subclassed a BaseAdapter similar to a simple Android list. So, I tried to set the text color in the getView() method like this (Your can see my attempt in between the commented section):
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
int sectionnum = 0;
for(Object section : this.sections.keySet()) {
Adapter adapter = sections.get(section);
int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) return headers.getView(sectionnum, convertView, parent);
if(position < size)
{
/***** I added this section to try to set the text color ***/
TextView captionTV = (TextView)adapter.getView(position, convertView, parent).findViewById(R.id.list_complex_caption);
captionTV.setTextColor(R.color.black;);
TextView titleTV = (TextView)adapter.getView(position, convertView, parent).findViewById(R.id.list_complex_title);
titleTV.setTextColor(R.color.black;);
/***** end add *****/
return adapter.getView(position - 1, convertView, parent);
}
// otherwise jump into next section
position -= size;
sectionnum++;
}
return null;
}
But what happens is that it sets the text color for the first cell, but does not set it for the rest.
Any ideas?
Hm. Nifty adapter.
The first thing to note here - modifying Views in the way you're doing is something best left to the layouts you use in the various section adapters, i.e. if you want black text, use an item layout that has black text.
To do it in code anyway you should not repeatedly call #getView(int, View, ViewGroup) on the sub-section adapters, instead do like this:
/**
* {#inheritDoc}
*/
public View getView(int position, View convertView, ViewGroup parent) {
int sectionnum = 0;
for(Object section : this.sections.keySet()) {
Adapter adapter = sections.get(section);
int size = adapter.getCount() + 1;
// check if position inside this section
if(position == 0) return headers.getView(sectionnum, convertView, parent);
if(position < size){
View view = adapter.getView(position - 1, convertView, parent);
TextView captionTV = (TextView) view.findViewById(R.id.list_complex_caption);
captionTV.setTextColor(R.color.black);
TextView titleTV = (TextView) view.findViewById(R.id.list_complex_title);
titleTV.setTextColor(R.color.black);
return view;
}
// otherwise jump into next section
position -= size;
sectionnum++;
}
return null;
}
Try to do it in bindView override the bindView function e.g.
#Override
public void bindView(View v, Context context, Cursor c) {
String name = c.getString(nameCol);
TextView captionTV = (TextView) v.findViewById(R.id.list_complex_caption);
captionTV.setTextColor(R.color.black);
}
At the moment I have this code running. I am working in eclipse and at the moment am getting this error
The method getItem(int) is undefined for the type Expandable.MySimpleCursorTreeAdapter
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
int childPosition, long id) {
// use groupPosition and childPosition to locate the current item in the adapter
Intent intent = new Intent(Categories.this, com.random.max.Random.class);
Cursor cursor = (Cursor) mscta.getItem(childPosition);
intent.putExtra("EMPLOYEE_ID", cursor.getInt(cursor.getColumnIndex("_id")));
//Cursor cursor = (Cursor) adapter.getItem(position);
//intent.putExtra("EMPLOYEE_ID", cursor.getInt(cursor.getColumnIndex("_id")));
startActivity(intent);
return true;
}
You using a Cursor Adapter, Cursors can only be iterated over (in a sequence).
So there is no getItem(position) method because you cant pick a specific item.
Use a different Adapter for your underlying DataModel like a ArrayAdapter.
Ok here some code for a AdapterImplementation
first:
YourCustomAdapter extends ArrayAdapter<YourDataObject>
than you simple implement the inherited Methods, the important Methods are getView and getItem
in getView you define how the Data will be shown in your ListView.
Use ViewHolder to cache your Items for scrolling.
#Override
public View getView(int position, View convertView, ViewGroup parent) {
final ViewHolder holder;
View v = convertView;
if (v == null) {
v = inflater.inflate(layoutResource, null);
holder = new ViewHolder();
holder.firstLine = (TextView) v.findViewById(R.id.textview);
v.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) v.getTag();
}
holder.firstLine = "test";
return v;
}
basicly you fill your holder with your stuff and save it inside your View, the next time your dont have to fill in your Resources again.
the second method getItem(int position) is simple:
you have to specify how to get the item on position "position" on your DataStructure.
If you have an Array you could write:
#Override
public long getItem(int position) {
return myDataArray.get(position);
}