I have a listview and each item has a title, some info, and a couple ImageViews I'm using as edit/delete buttons. I don't want to show these "buttons" unless the user selects the row. I can make the "buttons" invisible using:
DeleteButton.setVisibility(View.INVISIBLE);
EditButton.setVisibility(View.INVISIBLE);
in my BindView.
I can make the buttons visible in an onListItemClick:
ImageView DeleteButton = (ImageView) v.findViewById(R.id.button_delete);
ImageView EditButton = (ImageView) v.findViewById(R.id.button_edit);
DeleteButton.setVisibility(View.VISIBLE);
EditButton.setVisibility(View.VISIBLE);
What I can't do is make the "buttons" invisible when selecting another item or scrolling away.
The closest I found was to do a loop through the listitems in the current view and set them all to invisible before making the selected one visible:
protected void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
\\loop through all the items and set them back to invisible
for (int i=0;i<=l.getLastVisiblePosition();i++){
View vChild = l.getChildAt(i);
ImageView DeleteButton = (ImageView) vChild.findViewById(R.id.button_delete);
ImageView EditButton = (ImageView) vChild.findViewById(R.id.button_edit);
DeleteButton.setVisibility(View.INVISIBLE);
EditButton.setVisibility(View.INVISIBLE);
}
\\set the selected one visible
ImageView DeleteButton = (ImageView) v.findViewById(R.id.button_delete);
ImageView EditButton = (ImageView) v.findViewById(R.id.button_edit);
DeleteButton.setVisibility(View.VISIBLE);
EditButton.setVisibility(View.VISIBLE);
}
As you can guess...this approach only works if you have a few items.
I thought about adding a field to the SQLite database my list is using to keep track of the button visibility (similar to what you do for checkboxes) but that seemed silly. Please tell me there's another way.
Another way to do this would be to have an int field in your class that will remember the current position:
private int current = -1;
then in the onItemCLick() method use that field to hide/show your views:
#Override
protected void onListItemClick(ListView l, View v, int position, long id) {
// if it is the first click ignore this part
if (current != -1) {
View last = l.getChildAt(current); // the last one clicked
last.findViewById(R.id.button1).setVisibility(View.GONE); // kill it
}
v.findViewById(R.id.button1).setVisibility(View.VISIBLE);
current = position; // remember the new clicked position
}
If you want the views to be gone also when you scroll the list and those views aren't visible then in the bindView() method add the lines that hide the views:
//...
ImageView DeleteButton = (ImageView) view.findViewById(R.id.button_delete); // view is the view that you get as a parameter
ImageView EditButton = (ImageView) view.findViewById(R.id.button_edit);
DeleteButton.setVisibility(View.INVISIBLE);
EditButton.setVisibility(View.INVISIBLE);
//...
When the use scrolls the list all the views will have the Buttons visibility set to GONE and the onItemCLick() logic will work only for visible views.
I dont know if i understand your question correct but make the definitions of the ImageViews
ImageView DeleteButton = (ImageView) v.findViewById(R.id.button_delete);
ImageView EditButton = (ImageView) v.findViewById(R.id.button_edit);
one time at onCreate() and not every time again! Dont know if this solves your problem but try it.
Edit:
if(tempEditButton != null && tempDeleteButton != null){
tempDeleteButton.setVisibility(View.INVISIBLE);
tempEditButton.setVisibility(View.INVISIBLE);
}
EditButton.setVisibility(View.VISIBLE);
DeleteButton.setVisibility(View.VISIBLE);
tempEditButton = EditButton;
tempDeleteButton = DeleteButton;
This is an old question but I think I can still answer it. I solved this problem by creating a public static method which can be called from anywhere:
public static void hideOptions(Activity activity){
for (int i = 0; i< listviewSize; i++) {
Listview x = (Listview ) activity.findViewById(R.id.contactRecyclerView);
x.getChildAt(i).findViewById(R.id.myView).setVisibility(View.GONE);
}
}
You can then call this method whenever you want to hide your view
Related
I am developing a music playing app but I've been stuck with fixing a bug for the last two days. Here is a screenshot of the app. Basically the user can add a new view, name it however he wishes and choose a mp3 file to link to that view.
As you can see Every view has a text that a little play icon. This icon switches to a pause icon while the audio is playing. Here you can see the pause icon.
Issue 1:
When the user starts a sound and then click on another square, the previous sound stops as it should and the new sound begins, but the old square's icon stays the pause icon, and so on the screen eventally many squares will have the pause icon while not actually playing sound.
Issue 2: Let's say that the user clicks the absolute first square, which in the arrayList corresponds to position 0. Then the user scrolls down to the point that the square he clicked is no longer visible. When the user scrolls up again the square he clicked on will have the play icon set, while playing sound. I figured that's because in my GridAdapter i set every newly recicled view to have the play icon and I can't figure out how to set an if statement. How should the adapter know wether the box is playing a sound?
Many thanks and love.
GridItemAdapter.java:
public class GridItemAdapter extends ArrayAdapter<GridItem> {
private static final String LOG_TAG = GridItemAdapter.class.getSimpleName();
public GridItemAdapter(Activity context, ArrayList<GridItem> gridItems) {
// Here, we initialize the ArrayAdapter's internal storage for the context and the list.
// the second argument is used when the ArrayAdapter is populating a single TextView.
// Because this is a custom adapter for two TextViews and an ImageView, the adapter is not
// going to use this second argument, so it can be any value. Here, we used 0.
super(context, 0, gridItems);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Check if the existing view is being reused, otherwise inflate the view
View gridItemView = convertView;
if(gridItemView == null) {
gridItemView = LayoutInflater.from(getContext()).inflate(
R.layout.grid_item, parent, false);
}
// Get the {#link AndroidFlavor} object located at this position in the list
GridItem currentGridItem = getItem(position);
// Find the TextView in the list_item.xml layout with the ID version_name
TextView nameTextView = (TextView) gridItemView.findViewById(R.id.text_1);
// set this text on the name TextView
nameTextView.setText(currentGridItem.getSoundName());
ImageView playIcon = (ImageView) gridItemView.findViewById(R.id.image_1);
playIcon.setImageResource(R.drawable.play_ic);
// Return the whole list item layout (containing 2 TextViews and an ImageView)
// so that it can be shown in the ListView
return gridItemView;
}
}
MainActivity.java snippets of interest :
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
/*
if (lastPosition != -1) {
Log.v(TAG3, "Inisde if block, lastposition = " + lastPosition);
// Whatever position you're looking for
int firstPosition = gridView.getFirstVisiblePosition();
int wantedChild = lastPosition - firstPosition;
View wantedView = gridView.getChildAt(wantedChild);
Log.v(TAG3, "lastRow initiated, lastrow = " + wantedView);
ImageView lastIc = (ImageView) wantedView.findViewById(R.id.image_1);
lastIc.setImageResource(R.drawable.play_ic);
}
*/
togglePlayback(i, view);
lastPosition = i;
Log.v(TAG3, "outside if block, lastPosition = " + lastPosition);
}
});
public void togglePlayback(int i, View v){
final View view = v;
if(!isPlaying) {
releaseMediaPlayer();
ImageView playIc = (ImageView) view.findViewById(R.id.image_1);
playIc.setImageResource(R.drawable.pause_ic);
GridItem word = gridItems.get(i);
try {
mMediaPlayer = MediaPlayer.create(MainActivity.this, Uri.parse(word.getSoundPath()));
}catch (IllegalArgumentException e){
e.printStackTrace();
}
mMediaPlayer.start();
isPlaying = true;
mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
releaseMediaPlayer();
ImageView playIc = (ImageView) view.findViewById(R.id.image_1);
playIc.setImageResource(R.drawable.play_ic);
isPlaying = false;
}
});
}else{
releaseMediaPlayer();
ImageView playIc = (ImageView) view.findViewById(R.id.image_1);
playIc.setImageResource(R.drawable.play_ic);
isPlaying = false;
}
}
Here is a simple way to achieve it(I have not gone through your code since the snippet was not provided yet, the variables used below are self-explanatory):
First add a flag say isPlaying in the model class of an item in gridview
Now in getView method, add below code
if(itemList.get(index).isPlaying) {
//set the icon to pause one
} else {
//set the icon to playing one
}
Now, in view's click listener, add this
if(itemList.get(index).isPlaying) {
// write the code to pause the current song
} else {
// pause your <previousIndex> song
// play <index> item
itemList.get(index).isPlaying = true;
itemList.get(previousIndex).isPlaying = false;
previousIndex = index;
notifyDataSetChanged();
}
I have just written the basic logic, you need to write your code regarding playing/pause of your songs.
Hope this helps you.
today i was implementing a new feature in my app: showing a dialog with an EditText and requesting the soft keyboard, and i notice something really strange with my items in the sliding menu (I'm using the library from jfeinstein10)...
When the dialog shows and not the keyboard the items inside the sliding menu are okay, but when i also show the keyboard, the items change their background resource...
I tried using the log in the item click listener of the list inside the sliding menu but nothing it's called... So... Why it automatically change the background ?!
Hope you can help me :) And sorry for my english :D
The item click listener inside the sliding menu:
private AdapterView.OnItemClickListener slidingListItemClickListener = new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
// Unselected items
for (int j = 0; j < adapterView.getChildCount(); j++) {
View root = adapterView.getChildAt(j);
ImageView image = (ImageView) root.findViewById(R.id.partial_sliding_menu_list_image);
TextView text = (TextView) root.findViewById(R.id.partial_sliding_menu_list_text);
image.setBackgroundResource(SLIDING_MENU_ICON_NORMAL);
text.setTextColor( getResources().getColor(SLIDING_MENU_TEXT_NORMAL) );
}
// change the drawable of the selected item
ImageView image = (ImageView) view.findViewById(R.id.partial_sliding_menu_list_image);
TextView text = (TextView) view.findViewById(R.id.partial_sliding_menu_list_text);
image.setBackgroundResource(SLIDING_MENU_ICON_SELECTED);
text.setTextColor( getResources().getColor(SLIDING_MENU_TEXT_SELECTED) );
// Load the page clicked [it's a fragment.]
loadPage(i);
}
};
Some screenshots of the "error":
Click me
There is an really weird thing happening with my listview. I am creating an ListView with buttons and an editText.
It's disposed like this: [Button] [EditText] [Button], The buttons works like an "incrementer" and "decrementer" updating the numerical value of EditText in 1 unit per click.
The problem is, when I click in an button, almost every time an editText of another list view element is changed (the editText of the clicked item is also changed). And if I click in a button of this erroneous changed item, it also changes the editText of the first one. They basically have the same reference of buttons and editText, although they have textViews with data, and this data is different between they.
To accomplish that I created and custom adapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null) {
convertView = mInflater.inflate(R.layout.lastproduct_row, null);
holder = new ViewHolder();
holder.btnAddQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_add_qtd);
holder.btnSubQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_sub_qtd);
holder.etQuantidade = (EditText) convertView.findViewById(R.lastproduct_row.et_quantidade);
TextView tv;
holder.tvList = new TextView[PRODUCTROW_INT_KEY.length];
for(int i = 0; i < PRODUCTROW_INT_KEY.length; i++) {
tv = (TextView) convertView.findViewById(PRODUCTROW_INT_KEY[i]);
holder.tvList[i] = tv;
}
convertView.setTag(holder);
}
else {
holder = (ViewHolder) convertView.getTag();
}
HashMap<String, String> hm = productsList.get(position);
String key = hm.get(CODIGO_KEY);
for(int i = 0; i < PRODUCTROW_INT_KEY.length; i++) {
holder.tvList[i].setText(hm.get(PRODUCTROW_STR_KEY[i]));
}
holder.btnAddQtd.setTag(key+QTD_FLAG+ADD_ACTION);
holder.btnSubQtd.setTag(key+QTD_FLAG+SUB_ACTION);
holder.btnAddQtd.setOnClickListener(handle);
holder.btnSubQtd.setOnClickListener(handle);
if(novosEstoques.containsKey(key)) {
holder.etQuantidade.setText(MyParseFunctions.parseCentesimal(novosEstoques.get(key).getQuantidade()));
}
return convertView;
}
class ViewHolder {
private TextView []tvList;
private Button btnAddQtd, btnSubQtd;
private Button btnAddQtVol, btnSubQtVol;
private EditText etQuantidade, etQtVolume;
}
I added onClick listenners to the buttons, setting their tags with my listView element ID (concatenated with another informations). Then in my event listener I just get the button parent View (an LinearLayout) and get the EditText from that using getViewAt():
#Override
public void onClick(View v) {
String tag = (String) v.getTag();
if(tag.contains(QTD_FLAG)) {
String []info = ((String) v.getTag()).split(QTD_FLAG);
float qtd;
LinearLayout ll = (LinearLayout) v.getParent();
ll.setBackgroundColor(Color.rgb(0, 128, 30));
EditText et = (EditText) ll.getChildAt(2);
qtd = Float.parseFloat(et.getText().toString().replace(",", "."));
if(info[1].equals(ADD_ACTION)) {
qtd++;
}
else if(info[1].equals(SUB_ACTION)) {
if(qtd > 0)
qtd--;
}
Log.d("TESTE", "MODIFICAR KEY = "+info[0]);
et.setText(qtd+"");
}
}
I'm using an setBackgroundColor in this example to confirm that the LinearLayout instance is duplicated in the lisView. When I click an Button, it's painted in 2 different list view item.
Anyone can point me what could be doing this? I have found people with an duplicated ListView item, I don know if that is my case, cause I have TextView's inside my ListView, and they are not equal, only the LinearLayout portion with buttons and editText is "shared".
I make some changes in my getView method and it's working now! It seems that every time the getView method is called i have not guarantee at all that my editTexts will be filled properly and I didn't realize that. So every getView call I make I set the editText value, if the user edit an ET value, I store it in a HashMap to restore in getView, if there is no entry in HashMap for the given editText, then I set it to the default value (zero):
...
if(convertView == null) {
holder = new ViewHolder();
holder.btnAddQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_add_qtd);
holder.btnSubQtd = (Button) convertView.findViewById(R.lastproduct_row.btn_sub_qtd);
holder.etQuantidade = (EditText) convertView.findViewById(R.lastproduct_row.et_quantidade);
//Now it is easier to get etQuantidade reference in button
//click handle, I just have to do:
// public onClick(View v) {
// EditText etButtonAssociated = (EditText) v.getTag();
// ...
// }
holder.btnAddQtd.setTag(holder.etQuantidade);
holder.btnSubQtd.setTag(holder.etQuantidade);
holder.btnAddQtd.setOnClickListener(handle);
holder.btnSubQtd.setOnClickListener(handle);
...
}
else {
...
}
holder.etQuantidade.setTag(key);
if(novosEstoques.containsKey(key)) {
holder.etQuantidade.setText(MyParseFunctions.parseCentesimal(novosEstoques.get(key).getQuantidade()));
}
else {
holder.etQuantidade.setText("0");
}
return convertView;
Israel,
After looking over your code, I was wondering about an implementation decision you have made. Since each Button is "bound" to a particular EditText, have you considered setting the Tag of those Buttons to the EditText? The Tag may be any Object including a UI element. This is especially useful for dynamic UI elements, such as a runtime populated list.
Since this is handled in your Adapter you wouldn't have to worry about duplicate Parents and such. Additionally, you could avoid having to worry about "finding" the control in your onClick() because you would have it (It's the tag). I'm not sure exactly what your project needs are, but this seems like a potentially viable solution, unless you need those Buttons to accomplish other tasks.
Note of Caution
Just make sure that you erase the Tags' references to the EditText when you are done. Otherwise, you run the risk of leaking some memory.
FuzzicalLogic
listView=(ListView)findViewById(R.id.list);
listView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View viewItem, int position, long arg3) {
if(!itemClicked)
{
viewItem = parent.getChildAt(position);
((Button)viewItem.findViewById(R.id.gov)).setVisibility(View.VISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.VISIBLE);
viewItem.invalidate();
itemClicked=true;
clickedItemPos=position;
TextView text = (TextView)viewItem.findViewById(R.id.item);
ime = text.getText();
}
else
{
viewItem=parent.getChildAt(clickedItemPos);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.INVISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.INVISIBLE);
viewItem = parent.getChildAt(position);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.VISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.VISIBLE);
viewItem.invalidate();
clickedItemPos=position;
TextView text = (TextView)viewItem.findViewById(R.id.item);
ime = text.getText();
}
final int[] coordAndCat = FavoriteCoord(ime.toString());
Nullpointer exception happens when I have more elements and when you scroll and click the last item on the listview. How to workaround this?
Note: I'm trying to display 2 buttons in every item that is being clicked. This code works for all clicks on items besides the last one (if there are many elements in the list and you need to scroll)
clickedItemPos isn't defined after else unless clickedItemPos=position has been called earlier. What line does the error happen on?
listView=(ListView)findViewById(R.id.list);
listView.setOnItemClickListener(new OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> parent, View viewItem, int position, long arg3) {
if(!itemClicked)
{
viewItem = parent.getChildAt(position);
//start >> This might be where your problem is (R.id.gov)
((Button)viewItem.findViewById(R.id.gov)).setVisibility(View.VISIBLE);
//end <<
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.VISIBLE);
viewItem.invalidate();
itemClicked=true;
clickedItemPos=position;
TextView text = (TextView)viewItem.findViewById(R.id.item);
ime = text.getText();
}
else
{
viewItem=parent.getChildAt(clickedItemPos);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.INVISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.INVISIBLE);
viewItem = parent.getChildAt(position);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.VISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.VISIBLE);
viewItem.invalidate();
clickedItemPos=position;
TextView text = (TextView)viewItem.findViewById(R.id.item);
ime = text.getText();
}
final int[] coordAndCat = FavoriteCoord(ime.toString());
I think you said R.id.gov instead of R.id.go unless R.id.gov is truly an id you have. That is the only thing I saw 'wrong', please show a stacktrace for the error next time, it would help in debugging =)
EDIT
is clickedItemPos initialized somewhere else? because if it isn't this line: viewItem=parent.getChildAt(clickedItemPos); in your else statement would probably be null if nothing was selected before. I understand you want to use this in order to check for previously clicked items, but if nothing was clicked before, this will never get set to a value and therefore be null try doing this in that else statement to avoid the possible null variable:
else
{
if(clickedItemPos != null){ //only add this if there was a previous clicked item
viewItem=parent.getChildAt(clickedItemPos);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.INVISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.INVISIBLE);
viewItem = parent.getChildAt(position);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.VISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.VISIBLE);
viewItem.invalidate();
clickedItemPos=position;
TextView text = (TextView)viewItem.findViewById(R.id.item);
ime = text.getText();
}else{
viewItem = parent.getChildAt(position);
((Button)viewItem.findViewById(R.id.go)).setVisibility(View.VISIBLE);
((Button)viewItem.findViewById(R.id.re)).setVisibility(View.VISIBLE);
viewItem.invalidate();
clickedItemPos=position;
TextView text = (TextView)viewItem.findViewById(R.id.item);
ime = text.getText();
}
}
hopefully that will fix it. In your stack trace it says line 91 in your class is the line causing the error, what variable is located on that line? that is usually a good indicator of what variable is causing the null pointer, but since we don't know the line numbers for your code it is hard to guess where the issue is.
Yes there is repeated code in that solution but you could always make a method to put the repeated code in and call that instead if you want.
Good Luck, hope this helps.
I am using grid view with ImageAdapter to display images.
I have two set of images that is mThumbIds containing original images and cThumbIds containing the selected images.
Right now when i click on an image i change the normal image with the selected image. The code is as below:
final ImageView iv = (ImageView)v.findViewById(R.id.icon_image);
iv.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
//iv.setColorFilter(Color.LTGRAY);
iv.setImageResource(cThumbIds[position]);
//iv.bringToFront();
index= position;
}
});
iv.setImageResource(mThumbIds[position]);
But the problem arises when i click on the another image the other image also shows as selected. The correct way would be to show the new image as selected and remove the older one as selected .In other words the older one should revert back to original one.
Please help me on this
Thanks,
Pankaj
You need to create a variable and keep the clicked image's id in that. When the user clicks some other image, first reset the other image as per the id in the variable and then replace the variable value with the id of the currently clicked image.
I'm assuming you are using a modified copy of the ImageAdapter class in this tutorial and that the code you have posted is in the getView(int,View,ViewGroup) method of that class.
You save the index of the image that is selected but you don't save the view itself. You need to save both in order to revert the old image, something like this:
private int selectedPosition = -1;
private ImageView selectedView = null;
...
public View getView(int position, View convertView, ViewGroup parent) {
// I don't understand what this line is about??
ImageView iv = (ImageView) v.findViewById(R.id.icon_image);
// Why not something like this??
// ImageView iv = new ImageView(mContext);
iv.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
// Set the selected image for the ImageView just pressed.
iv.setImageResource(cThumbIds[position]);
// Revert to the original image for the ImageView previously
// pressed.
if (selectedPosition != -1) {
selectedView.setImageResource(mThumbIds[selectedPosition]);
}
// Save the position and ImageView just pressed so it can be
// reverted next time an ImageView is pressed
selectedPosition = position;
selectedView = (ImageView) view;
}
});
iv.setImageResource(mThumbIds[position]);
return (iv);
}
I'm a bit confused about the line ImageView iv = (ImageView) v.findViewById(R.id.icon_image); though (as I mention in my code example).