I am facing some problem using a listview to highlight a single item. I've created an anonymous adapter as in the code below but when the list is displayed several items have the highlight/bold. The log trace shows the bold/background only being called once and yet several items have the bold but only the correct one has the background color set. I separated the background color setting for debugging but the results are the same if I use only one if(position==selection) check.
Note that this is not an interactive listview, no onclicklistener needed.
I would greatly appreciate any help. Thank you in advance.
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, times) {
#Override
public View getView(int position, View cview, ViewGroup group) {
int count = 0; //used for debugging
View view = super.getView(position, cview, group);
TextView tv = (TextView)view.findViewById(android.R.id.text1);
Typeface tf = tv.getTypeface();
Log.d("log", "position = " + position);
if(position == selection) {
tv.setTypeface(tf, Typeface.BOLD);
Log.d("log", "BOLD" + position + "count=" + (count ++));
} else {
tv.setTypeface(tf, Typeface.NORMAL);
}
if(position == selection) {
view.setBackgroundColor(Color.LTGRAY);
Log.d("log", "Bkgnd " + position + "count: " + count);
} else {
view.setBackgroundColor(Color.WHITE);
}
return view;
}
};
I just wanted to add to this in case someone checks it. A good solution is as follows:
public View (int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.mylayout, parent, false);
}
TextView textView = convertView.findViewById(R.id.mytextview);
if(position == selection) {
textView.setBackgroundColor(Color.parseColor("#88FFFFFF");
} else {
textView.setBackgroundColor(Color.parseColor("#00000000");
}
return convertView;
}
What this does is set the background color to white with 50% alpha for the selection and 0% alpha, transparent, for the non-selection. This makes the selected item a little brighter but the same color.
A similar effect can be found by setting android:listSelector to "#88FFFFFF" in xml but doing it in the getView() function allows one to highlight more than one element differently while keeping the same color theme. I used this in my program to highlight some items in a listview with "#88000000" a darker item plus the "#88FFFFFF" for the selected item.
anyway, not sure if anyone will come across this but I found it helpful once I figured it out
Apparently, there is some "magic" with typefaces. I've changed the part that is responsible for setting the typeface as follows:
if(position == selection) {
tv.setTypeface(Typeface.create(tf, Typeface.BOLD));
}
else {
tv.setTypeface(Typeface.create(tf, Typeface.NORMAL));
}
and it works as expected.
Related
I am building a todo application. My goal is for the item's background color to change to red and the font to white, if urgent = true (boolean).
I am able to do this, but unfortunately once it changes the true todo, it will also change the todo before, even if it equals false.
I know the issue is in the getView method (see below). I have tried moving the textView = newView.findViewById(R.id.textView), above the if old == null statement, but that seems to crash the app. I have also moved the if urgent == true statement into the other if statement, and that won't work either.
Any ideas what may be causing the issue?
#Override
public View getView(int position, View old, ViewGroup parent) {
View newView = old;
LayoutInflater inflater = getLayoutInflater();
if(old == null) {
newView = inflater.inflate(R.layout.todo_items, parent, false);
}
textView = newView.findViewById(R.id.textView);
textView.setText(getItem(position).toString());
if(urgent == true) {
newView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
}
return newView;
}
}
You need an array of booleans to keep track of the state for each item in the listview
Try changing
if(urgent == true) {
newView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
}
To
if(urgent[position]) {
newView.setBackgroundColor(Color.RED);
textView.setTextColor(Color.WHITE);
} else {
//Put here the default colors
newView.setBackgroundColor( );
textView.setTextColor( );
}
this should fix the issue, also you don't need to do if(boolean == true) if(boolean) is enough
I think you need to have an array (or list) of urgent variables, for each position in the list. When item in the list is updated by scroll of by other reason, all views are updated according to the one urgent var.
I'm using a GridView to show a list of "vehicles" (a rectangle displaying some short informations about the vehicle) and when i click on a rectangle, it expands the view to show more informations.
That's works fine.
But when i want to rebuild my gridview with other datas, the clicks aren't caught anymore by the gridview's childs.
I didn't want to use some onItemClickListener because it's just a show/hide feature on childs...
So I set onClickListener in the getView() function of my custom adapter.
Here's my adapter code :
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View rowView = convertView;
if (rowView == null) {
LayoutInflater inflater = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflater.inflate(R.layout.encart_vehicule, parent, false);
final ViewHolder vh = new ViewHolder();
vh.text = (TextView) rowView.findViewById(R.id.libVehi);
vh.text2 = (TextView) rowView.findViewById(R.id.heureEngagement);
vh.back = (LinearLayout) rowView.findViewById(R.id.backcolor);
vh.listEq = (LinearLayout) rowView.findViewById(R.id.equipage);
vh.vIndicator = (View) rowView.findViewById(R.id.view1);
vh.more = (TextView) rowView.findViewById(R.id.more);
vh.vIndicator.setVisibility(View.GONE);
vh.listEq.setVisibility(View.GONE);
if (mlistMoyenMateriel.get(position).getLstPersonnels().size() == 0) {
vh.more.setVisibility(View.GONE);
} else {
rowView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (!vh.opened) {
vh.more.setVisibility(View.GONE);
vh.vIndicator.setVisibility(View.VISIBLE);
vh.listEq.setVisibility(View.VISIBLE);
} else {
vh.more.setVisibility(View.VISIBLE);
vh.vIndicator.setVisibility(View.GONE);
vh.listEq.setVisibility(View.GONE);
}
vh.opened = !vh.opened;
}
});
}
vh.back.setBackgroundColor(Color.parseColor("#"
+ mlistMoyenMateriel.get(position).getEtat()
.getm_strColor()));
for (Personnel p : mlistMoyenMateriel.get(position)
.getLstPersonnels()) {
TextView tv = new TextView(getContext());
tv.setText(p.getm_strNom() + " " + p.getm_strPrenom() + " "
+ p.getm_strMatricule());
Resources r = getContext().getResources();
float px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 5, r.getDisplayMetrics());
tv.setPadding(0, 0, 0, (int) px);
vh.listEq.addView(tv);
}
rowView.setTag(vh);
}
ViewHolder holder = (ViewHolder) rowView.getTag();
holder.text.setText(mlistMoyenMateriel.get(position).getType()
+ " "
+ mlistMoyenMateriel.get(position).getNumeroOrdre()
.substring(1) + " "
+ mlistMoyenMateriel.get(position).getCode_centre());
holder.text2.setText(dateUtil.Date_heureToString(mlistMoyenMateriel
.get(position).getdEngagement(), "dd MMMMMMMM HH:mm")
+ (mlistMoyenMateriel.get(position).getDureeASLL() == null ? ""
: "+" + mlistMoyenMateriel.get(position).getDureeASLL()
+ "mn"));
holder.back.setBackgroundColor(Color.parseColor("#"
+ mlistMoyenMateriel.get(position).getEtat().getm_strColor()));
// holder.back.setBackgroundColor(Color.parseColor("#"+mlistMoyenMateriel.get(position).getEtat().getm_strColor()));
return rowView;
}
Then my gridView instantiation :
GridView gv = null;
gv = (GridView) rlInter
.findViewById(R.id.listAutresVehiculesEngages);
gv.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
MoyenMaterielAdapter mma = new MoyenMaterielAdapter(this,
inter.getm_lstListeDesobjetVehiculePourCetteOperation());
gv.setAdapter(mma);
gv.invalidateViews();
When i recall this code a second time, the list is correctly rebuilt but, even if it pass in the "rowView.setOnClickListener" from the getView function, the clicks on childs does not have effect anymore (it did not expand my views). I tried to make a Toast on the click event, it is not show anymore too.
Does anyone knows about this issue? What I am doing wrong? I could try with a OnItemClickListener, but I think it will be a little bit too much for that little feature, knowing that still works but only the first time...
Thanks for your help!
(i'm really sorry for my english)
EDIT:
I missed something : at the second time it did NOT pass in the setOnClickListener code. Even if I got the new items displayed.
Add as first line in onClick() ViewHolder vh =(ViewHolder)v.getTag();.
rowView is only null the first time your list loads.
Move your onclick to outside the if (rowView == null) block. Also, it is recommended to use the holder pattern in list adapters.
I have a custom adapter that renders two (2) checkboxes, a picture and the name of the client. All the information needed for the adapter is fetched from an ArratList that contains the Client class.
Every row needs to have both checkboxes checked (selected) for the client in order to process the purchase order, in case that a particular client has one checkbox checked-off and the other checkbox not, that raises a flag as MISMATCH. To make a valid order both checkboxes need to be checked-off.
We are implementing a button for verification, which will find any mismatch in the adapter and then hightlight the mismatches.
EDITION: After pressing the verificationBtn I am able to identify if any row has mismatch on checkboxes, for example, if checkbox1 was checked and checkbox2 not. that will mark the row as mismatch. I am using the position of my checkboxes based on clientList that is an arraylist of List clientList.
QUESTION: How can I get the position that the viewHolder has in order compare against the clientList position? Is there any way I can force the viewHolder to store the position and get it back and make the comparison with cli.getClient_number() ?
So far I have tested two different ways with no luck:
Method 1:
viewHolder.clientName.setBackgroundColor((Interger.parseInt(cli.getClient_number()) ) == position ? Color.GREEN : Color.TRANSPARENT);
Method 2
viewHolder.clientName.setBackgroundColor(Color.GREEN);
here the code that I am implementing.
// This goes in my main Client Activity
Button verificationBtn = (Button) findViewById(R.id.verificationBtn);
verificationBtn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
buffer.setLength(0);
mismatchTv.setText("");
for (Client cli : clientList) {
if (cli.isCheckboxOneSelected() != cli.isCheckboxTwoSelected()) {
//We had defined above the following buffer = new StringBuffer();
buffer.append((ah.parseInt(cli.getClient_number(), 0) - 1) + ", ");
cli.setMismatch(true);
//We are passing here the ID that correspond to the client mismatch
list_adapter.setBackgroundColor(Integer.parseInt(cli.getClient_number()) - 1);
setListAdapter(list_adapter);
Log.w("cli.getClient_number() ", String.valueOf(Integer.parseInt(cli.getClient_number()) - 1));
}
}
// We display any mismatch on a TextView on top of the screen
if (buffer.length() != 0) {
//This is a TextView on top of the screen
mismatchTv.setText("Error en Client(s) "
+ buffer.toString());
}
// This goes inside of the ClientArrayAdapter
public void setBackgroundColor(int position) {
Log.w("inside of setBackgroundColor method", "True");
switchIndex = 1;
positionFetched = position;
}
// This goes inside of the ClientArrayAdapter
// and inside the body of public View getView(int position, View convertView, ViewGroup parent) {
switch (switchIndex) {
case 1:
viewHolder.cbone
.setButtonDrawable(R.drawable.btn_checkbox_selector);
viewHolder.cbtwo
.setButtonDrawable(R.drawable.btn_checkbox_selector);
Log.w("switch 1 was called ", "True");
for (Client cli : clientList) {
if (cli.isCheckboxOneSelected() != cli.isCheckboxTwoSelected()) {
Client cli = getItem(positionFetched);
if (cli.isMismatch()) {
cli.setColor(Color.BLACK);
Log.e("if (cli.isMismatch()) ", "");
//HERE WE ARE TRYING TO HIGHLIGHT THE ROW WITH MISMATCH
//WHY THIS LINE DOES NOT WORK?
//THE ISSUE THAT I AM GETTING IS THAT I CANNOT CONTROL WHAT ROW TO AFFECT
//IN THE VIEW HOLDER
viewHolder.clientName.setBackgroundColor(Color.GREEN);
}
}
}
break;
default:
viewHolder.cbone.setButtonDrawable(R.drawable.disabled_cb);
viewHolder.cbtwo.setButtonDrawable(R.drawable.disabled_cb);
break;
}
// This goes inside of the ClientArrayAdapter
static class ViewHolder {
public TextView clientName;
public TextView clientNumber;
public ImageView imageView;
public CheckBox cbtwo;
public CheckBox cbone;
public int position;
}
After three days trying to figure out what's wrong with this code, I finally found the solution moving the Method #1 just at the very end of the getView method. :-)
I have been trying to visually indicate the state of a single element in the list generated by ParseQueryAdapter but the code below changes the background color of multiple rows.
Have tried to log whenever the setBackgroudColor is called and this seems correct, so it must be due to android reusing the view I guess.
#Override
public View getItemView(final ParseObject object, View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(),
R.layout.view_circuitunit_adapter_item, null);
}
super.getItemView(object, v, parent);
final CircuitUnitStarted circuitUnitStarted = (CircuitUnitStarted) object;
if (circuitUnitStarted.getTimeEnded() != null) {
v.setBackgroundColor(Color.LTGRAY);
}
return v;
}
A simple solutions seems to always color either white or grey:
if (circuitUnitStarted.getTimeEnded() != null) {
v.setBackgroundColor(Color.LTGRAY);
} else {
v.setBackgroundColor(Color.WHITE);
}
Do not know why I did not think of that before
I download a custom table from this site.
I want to show the value of the cell I click.
TableFixHeaders table = (TableFixHeaders) findViewById(R.id.table_1);
table.setAdapter(new MyAdapter(this));
table.setOnLongClickListener(new OnLongClickListener(){
#Override
public boolean onLongClick(View v) {
TextView Cl = (TextView) table.getChildAt(1);
Toast.makeText(this, Cl.getText().toString(), Toast.LENGTH_LONG).show();
return false;
}
});
The problem is I can't intercept any event in my main activity.
I also have downloaded this very nice widget with scrolling columns and rows. And I also needed to get a response on a click at a certain cell. It didn't come, but I found the reason here:
In TableFixHeaders.java, module OnTouchEvent(MotionEvent event) add this line at the beginning:
super.onTouchEvent(event);
This call will make sure that other touch methods gets called! So it should also work for longclicks as well!
I have added my click-handler to the specific view (cell) in module GetView(int row, int column, View convertView, ViewGroup parent) when convertView is inflated first time. Then I an able to have different handlers to different cells (columns-headers, data-cells etc).
Here is the detailed code:
private View getBody(final int row,final int column, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.item_table, parent, false);
}
/*if(row == 8){
convertView.setBackgroundResource(R.color.row8); //if row8 need different colour
}*/else {
//Change table color using bg_table_col
convertView.setBackgroundResource(row % 2 == 0 ? R.drawable.bg_table_color1 : R.drawable.bg_table_color2);
}
((TextView) convertView.findViewById(android.R.id.text1)).setText(records.get(row).getItem(column + 1));
convertView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
detailsearchPaperID = records.get(row).getItem(0);
final String S;
S = detailsearchPaperID + " : " + records.get(row).getItem(column + 1);
Log.d(TAG, S);
Toast.makeText(getApplicationContext(), S, Toast.LENGTH_SHORT).show();
//...
// we will not start intent here but after performing search
return true;
}
});
return convertView;
}
If you add the listener as explained in previous post (when convertView is inflated first time), this will work only on the first view, before performing any scroll.
My code works even if you have performed scroll. Of course you need to add
super.onTouchEvent(event);
as explained earlier
I'm using this wrapper for InqBarna's library.
This is a code snippet of how to achieve the click events on table body.
You can see more ellaborated examples here.
TableFixHeaderAdapter.ClickListener<List<String>, BasicCellViewGroup> clickListenerBody = new TableFixHeaderAdapter.ClickListener<List<String>, BasicCellViewGroup>() {
#Override
public void onClickItem(List<String> array, BasicCellViewGroup viewGroup, int row, int column) {
viewGroup.vg_root.setBackgroundColor(ContextCompat.getColor(context, R.color.colorYellow));
Snackbar.make(viewGroup, "Click on " + viewGroup.textView.getText() + " (" + row + "," + column + ")", Snackbar.LENGTH_SHORT).show();
}
};
and so on for the rest of the table cells:
adapter.setClickListenerFirstHeader(clickListenerHeader);
adapter.setLongClickListenerFirstHeader(longClickListenerHeader);
adapter.setClickListenerHeader(clickListenerHeader);
adapter.setLongClickListenerHeader(longClickListenerHeader);
adapter.setClickListenerFirstBody(clickListenerBody);
adapter.setLongClickListenerFirstBody(longClickListenerBody);
adapter.setClickListenerBody(clickListenerBody);
adapter.setLongClickListenerBody(longClickListenerBody);
adapter.setClickListenerSection(clickListenerBody);
adapter.setLongClickListenerSection(longClickListenerBody);
Hope it helps you.