I have set mButton.setClickable(false); in my code but still this button is invoked by global button.setOnClickListener of my code.
EDIT: sorry for the delayed update. Below is the details view where I face the issue.
inside my listview customAdapter class getView method
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
YourWrapper wrapper = null;
HashMap<String, Object> cTa= new HashMap<String, Object>();
cTa= d.getPosition(position)
Button mButton = (Button)convertView.findViewById(R.id.mBtn);
if (row == null)
{
row = inflater.inflate(R.layout.layout, parent, false);
wrapper = new YourWrapper (row);
row.setTag(wrapper);
}
else
wrapper = (YourWrapper) row.getTag();
if(success)
{
// section-1
mButton.setClickable(true);
}
else{
// section-2
mButton.setClickable(false);
mButton.setFocusable(false);
}
wrapper.getButton().setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
//operation
}
});
return row;
}
Above is the current code which working,and on section-2 it makes the mButton clickable- false, and focusable - false but still it's listen the below wrapper.getButton().setOnClickListener() and perform the operation. Please suggest me. Sorry for delayed update. Thanks!
UPDATE: I have made below hot-fixes that solve the problem for now.
// section-2
mButton.setVisibility(View.GONE);
mButton.setClickable(false);
mButton.setFocusable(false);
That seems to be by design. This is from the documentation of the View.setOnClickListener method:
Register a callback to be invoked when this view is clicked. If this view is not clickable, it becomes clickable.
Instead of using setClickable(false) use setEnabled(false)
Put setClickable after setOnClickListener
mBtn.setOnClickListener(this);
mBtn.setClickable(false);
if you put setClickable(false) before setOnClickListener(this), it doesn't work.
Instead of using setClickable(false) use following
button.setFocusableInTouchMode(false);
I had the same problem in my app where i needed to set my button not to clickable in certain conditions. this worked for me. Hope this helps.
Use View.setOnClickListener() before View.setClickable() ,or the method setOnclickLisnter() will set the flag true.
I'm not sure if you're still looking for the answer, but for some weird reason
mBtn.setClickable(true);
stops the view from getting clicked and
mBtn.setClickable(false);
makes it clickable again.
on xml
android:enabled="false"
android:alpha="0.5"
dynamically
yourButtonId.alpha = 0.5f
yourButtonId.isEnabled = false
You can check like if(!view.isClickable()) return;
This will work in case of Imageview as well as the button.
private OnClickListener onClickListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (imageview.isEnabled()){
//I have wrapped all code inside onClick() in this if condition
//Your onClick() code will only execute if the imageview is enabled
//Now we can use setEnabled() instead of setClickable() everywhere
}}
};
Inside onCreate(), you can do setEnabled(false) which will be equivalent to setClickable(false).
We are able to use setEnabled() as tag because it's state remains uneffected on invocation of click (unlike setClickable() whose state changes).
Like Other friends said, setOnClickListener will override the flag to true. So the Workaround is to setOnTouchEvent return true whenever you want to disable clicks and set it to retrun false when you want to enable click events. This is because onTouchEvent is called before every clickListener you define for a view, so returning true will say to all listeners that :
"Ok, I received this event here, nobody else can receive it".
So your solution may be something like this:
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
YourWrapper wrapper = null;
HashMap<String, Object> cTa= new HashMap<String, Object>();
cTa= d.getPosition(position)
Button mButton = (Button)convertView.findViewById(R.id.mBtn);
if (row == null)
{
row = inflater.inflate(R.layout.layout, parent, false);
wrapper = new YourWrapper (row);
row.setTag(wrapper);
}
else
wrapper = (YourWrapper) row.getTag();
if(success)
{
// section-1
mButton.setOnTouchListener((v, event) -> false);
}
else{
// section-2
mButton.setOnTouchListener((v, event) -> true);
}
wrapper.getButton().setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
//operation
}
});
return row;
}
Set the click listener to null
someView.setOnClickListener(null)
As #Jan notes, the setOnClickListener enables the click listener automatically. Therefore, a null click listener can be set to disable future clicks. After setting the view to a null click listener, there are no adverse effects to future clicks on that view.
I wanted to do it on Spinner, and only this one worked for me:
spinner.setOnTouchListener { v, event ->
return#setOnTouchListener true
}
I just checked setClickable(true) and setClickable(false) on Android 4.1.1 and it seems to be working now.
Related
I m new here and I've got a question for which I haven't found answer yet.
I am trying to get some variable value from a clicked object using onClickListener.
This view is an object (actually its a ConstraintLayout) created previously with a boolean value.
Code (that is not the current code I've got but you get the idea hopefully):
public class layoutView extends ConstraintLayout {
boolean bool = false;
public layoutView (Context context) {
super(context);
}
...
}
I am adding this layoutView into my main layout and its working fine but I need to get this boolean value when i click the layout view.
layoutView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
v.setBackgroundColor(Color.GREEN); //this works fine
boolean check = v.bool //this wouldnt work
if (v.bool == true)... //this woulnt work
}
});
Is it possible at all. How to approach this?
Thanks in advance!
You can try layoutView.setTag()/getTag() instead of keeping your own variable bool.
Note that you may need to use a Boolean object instead of primitive type, for example:
layoutView.setTag(new Boolean(true));
// inside on click listener
if (v.getTag() == true) {
// do something
}
I have a ListActivity that implements onListItemClick() and calls a doSomething() function of the class. The latter contains l.setSelection(position) where l is the ListView object.
Now there is a onClickListener() listening for a button click that perfoms some actions and that too calls doSomething().
In the first case, the selected item get positioned appropriately, but in the latter, nothing happens.
Any clues about this strange behaviour and how I might make it work?
maybe you need to use function:
ListView.setItemChecked(int position, boolean checked);
use requestFocusFromTouch() before calling setSelection() method
I know this is an old question but I just had a similar problem that I solved in this way:
mListView.clearFocus();
mListView.post(new Runnable() {
#Override
public void run() {
mListView.setSelection(index);
}
});
You might need to wrap setSelection() in a posted Runnable (reference).
setSelection() does not necessarily have visual impact. The selection bar only appears if you use the D-pad/trackball to navigate the list. If you tap on the screen to click something, the selection bar appears briefly and vanishes.
Hence, setSelection() will only have a visual impact if the activity is not in touch mode (i.e., the last thing the user did was use the D-pad/trackball).
I am not 100% certain this explains your phenomenon given the description you provided, but I figured it is worth a shot...
If you use an Adapter for your ListView add this code to your adapter:
public class MyAdapter extends
ArrayAdapter<MyClass> {
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
LayoutInflater inflator = (LayoutInflater) getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
rowView = inflator.inflate(R.layout.my_adapter, null);
} else {
rowView = (View) convertView;
}
//...
// set selected item
LinearLayout ActiveItem = (LinearLayout) rowView;
if (position == selectedItem)
{
ActiveItem
.setBackgroundResource(R.drawable.background_dark_blue);
// for focus on it
int top = (ActiveItem == null) ? 0 : ActiveItem.getTop();
((ListView) parent).setSelectionFromTop(position, top);
}
else
{
ActiveItem
.setBackgroundResource(R.drawable.border02);
}
}
private int selectedItem;
public void setSelectedItem(int position) {
selectedItem = position;
}
}
In your Activity:
myAdapter.setSelectedItem(1);
For me calling
listView.notifyDataSetChanged();
listView.requestFocusFromTouch();
and then
listView.setSelection(position);
solved the issue.
if you do that in a runnable it works without calling requestFocusFromTouch(), but the old position of the ListView is showen for a sekound.
I have an very large Request with Webcontent. When I used the code in onCreateView the Listview wasnt even finished loading.
I put it in onPostExecute of my AsyncTask.
//Get last position in listview
if (listView != null && scrollPosition != 0) {
listView.clearFocus();
listView.requestFocusFromTouch();
listView.post(new Runnable() {
#Override
public void run() {
listView.setItemChecked(scrollPosition, true);
listView.setSelection(scrollPosition);
}
});
}
Dont forget to set the item checked in on Click ;)
Maybe you should use the smoothScrollToPosition(int position) method of ListView
You can try 2 ways like these:
Solution A:
mListView.post(new Runnable() {
#Override
public void run() {
if (null != mListView) {
mListView.clearFocus();
mListView.requestFocusFromTouch();
mListView.setSelection(0);
}
}
});
In some complicated situation, this solution will bring some new problems in Android 8.x. Besides it may cause unexpected onFocusChange().
Solution B:
Define a custom view extends ListView. Override method handleDataChanged().Then setSelection(0). In CustomListView:
#Override
protected void handleDataChanged() {
super.handleDataChanged();
if (null != mHandleDataChangedListener){
mHandleDataChangedListener.onChanged();
}
}
HandleDataChangedListener mHandleDataChangedListener;
public void setHandleDataChangedListener(HandleDataChangedListener handleDataChangedListener) {
this.mHandleDataChangedListener = handleDataChangedListener;
}
public interface HandleDataChangedListener{
void onChanged();
}
In activity:
mListView.setHandleDataChangedListener(new CustomListView.HandleDataChangedListener() {
#Override
public void onChanged() {
mListView.setHandleDataChangedListener(null);
mListView.setSelection(0);
}
});
mAdapter.notifyDataSetChanged();
Ok, That's it.
In my case smoothScrollToPosition(int position) worked, can you also tell me how to set that scrolled position into center of the list. It appeared at the bottom of visible items.
For me it helped to set
ListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); or ListView.CHOICE_MODE_MULTIPLE
then
ListView.setSelection(position) or ListView.setItemChecked(position, true);
works fine
Found a solution in my case. I am not using a Runnable since my class is extending ListFragment. What I had to do is make my index a final;
final index = 5;
mListView.setSelection(index);
I found that sometimes setSelection will not work because I set attribute "android:height" of listView to "wrap_content".
And the times my App won't work is that when listView become scrollable from non-scrollable.
For example, if my app is "File Browser App". When my list is less than, let's say 6, then it's non-scrollable. Now I return to the parent directory, and it has 11 objects, and I want to set selection to some position, and it won't work here.
to\from | Scrollable | non-Scrollable
Scrollable | O | O( of course )
non-Scrollable | X | O( of course )
I don't want to use post(Runnable), because there will has delay.
==================================
Answer:
You can try to set "android:height" to "match_parent"
God, it spends three days.
When use post to setSelection(), the ListView will see first , then scroll to the position , thank to "魏經軒", then layout actually will effect the setSelection(), because setSelection() call the setSelectionFromTop(int position, int y), there is another way to solve it.
listView.setAdapter(listView.getAdapter());
listView.setSelection(123);
For me the solution to this problem was:
listView.clearChoices();
Simply try this code
listView.setAdapter(adapter);
listView.setSelection(position);
adapter.notifyDataSetChanged();
Trudging my way through my introduction to Java and Android on a simple app and have run into an issue with ListView item selection. For one of my activities, I have a layout with two buttons, one of which is a "Delete" button, and a ListView of "passages" which are essentially timestamps for when a device has passed a sensor.
I have implemented the ability to click on an item to select it, which then enables the "Delete" button. A click of the "Delete" button removes the "passage" but I still end up with a selected item, which I don't want.
To implement selection, I added the following property to the ListView:
android:id="#+id/passagesListView"
android:choiceMode="singleChoice"
android:listSelector="#666666"
Selection is supported in OnCreate via a an OnItemClickListener:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_passages);
passagesViewAdapter = new PassagesViewAdapter(this, R.layout.passages_row_layout, passages);
final ListView passagesListView = (ListView) findViewById(R.id.passagesListView);
assert passagesListView != null;
final Button deleteButton = (Button) findViewById(R.id.deleteButton);
deleteButton.setEnabled(false);
buildPassageList();
passagesListView.setAdapter(passagesViewAdapter);
passagesListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View view, int position,long arg3) {
Toast.makeText(ViewPassagesActivity.this, "position is " + position,
Toast.LENGTH_LONG).show();
view.setSelected(true);
passagesViewAdapter.notifyDataSetChanged();
selectedItemPos = position;
deleteButton.setEnabled(true);
}
});
}
This part works. However, there is some issue with deletion. As you can see in the comments, I have tried several methods that I found on StackOverflow that seemed to apply but, although I am able to delete the correct item from the list, I am still ending up with a selected item after the call to delete().
public void delete (View view)
{
final Button deleteButton = (Button) findViewById(R.id.deleteButton);
ListView passagesListView = (ListView) findViewById(R.id.passagesListView);
if(selectedItemPos != -1)
{
Toast.makeText(ViewPassagesActivity.this, "remove " + selectedItemPos,
Toast.LENGTH_LONG).show();
// This did not work, which is strange since it worked similarly for selection when clicked
// View itemView = passagesListView.getChildAt(selectedItemPos);
View itemView = passagesViewAdapter.getView(selectedItemPos, null, passagesListView);
itemView.setSelected(false);
// This was also recommended in various posts on StackOverflow.
// Not clear whether clearChoices applies only to checkBoxes?
// passagesListView.clearChoices();
// passagesListView.requestLayout();
passages.remove(selectedItemPos);
deleteButton.setEnabled(false);
selectedItemPos = -1;
passagesViewAdapter.notifyDataSetChanged();
}}
}
I also ran into some issues trying to track which item is selected via setSelected() and getSelectedItemPosition() and punted by just tracking the index myself. So, as I am new to this, I'm sure there is something I am not understanding about Views or maybe something else such as a misunderstanding of how selection works?
How can I clear the selection?
Thanks!
I don't know what your PassagesViewAdapter class looks like. Maybe you can try
passagesViewAdapter.remove(passages.get(selectedItemPos));
passages.remove(selectedItemPos);
deleteButton.setEnabled(false);
selectedItemPos = -1;
passagesViewAdapter.notifyDataSetChanged();
I have got a list view with 9 rows in it. Every row has two TextViews and a ImageButton which plays a song specific for that row. If it is playing one of the two TextViews should change color and change the text every second to get a result like '1:12 - 7:35'. And that's where my problem lies.
The first time the list view loads all elements that are on screen work fine but whenever I scroll down, tap on the playButton it highlights the wrong cell. Probably because list view's position returns the position on the screen and not the position in the list.
private MediaPlayer mp;
private Handler handler;
private int playingCellPosition = -999;
public View getView(final int position, View convertView, final ViewGroup parent) {
// Find the oefening to work with
final Oefening currentExercise = myExercises.get(position);
LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View itemView = vi.inflate(R.layout.cell, null);
// Get textviews
final TextView durationTextView = (TextView) itemView.findViewById(R.id.cell_duur);
final Runnable updateDurationTextView = new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable(){
public void run(){
Oefening playingExercise = currentExercise.get(playingCellPosition);
TextView durationTextViewToUpdate = (TextView) parent.getChildAt(playingCellPosition).findViewById(R.id.cell_duur);
durationTextViewToUpdate.setText(getFormattedCurrent(mp.getCurrentPosition()) + " - " + playingExercise.getDuration());
durationTextViewToUpdate.setTextColor(Color.parseColor("#b71393"));
}
});
handler.postDelayed(this, 1000);
}
};
ImageButton playButton = (ImageButton) itemView.findViewById(R.id.cell_playButton);
playButton.setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
if (mp.isPlaying()) {
// Pause it here. Not very important to this problem since it occurs when it starts playing and not when it stops
mp.pause();
v.setBackgroundResource(R.drawable.play_icon);
durationTextView.setText(currentExercise.getDuration());
durationTextView.setTextColor(Color.BLACK);
handler.removeCallbacks(updateDurationTextView);
} else {
mp = MediaPlayer.create(MainActivity.this, currentExercise.getAudioFile());
mp.start();
v.setBackgroundResource(R.drawable.pause_icon);
handler.post(updateDurationTextView);
}
}
});
}
The Oefening playingExercise = currentExercise.get(playingCellPosition); works fine though, since it shows the information of the cell whose play button I tapped on. It just shows the information on the wrong cell.
As Áron Nemmondommegavezetéknevem pointed out, the problem is in parent.getChildAt(...);
Note 1: I don't reuse views with convertView since that messed up positions a lot. This is the closest I have come to what I have to achieve.
Note 2: I left out a lot of the code for the MediaPlayer. It is constructed well, so don't worry about that.
Note 3: If someone has a better suggestion for a title, please edit this one. Couldn't come up with a better one.
The problem is obviously with
parent.getChildAt(...);
In the case of a ListView it doesn't return the view of the specific position. Actually it's quite unpredictable what it returns with.
To illustrate why it doesn't return with the view of the specified position: imagine a list view with 10000 or more items. ListView has only a few views, and doesn't have views for all the 10000 items. What could it return with if you would request the 2786. view? Nothing, it doesn't have a view for that item.
Edit:
Suggestion:
Although I don't see how your code works, you should store which item view belongs to an individual item. For example, you can call setTag(position) on convertView before you return with it. Then you can write a function which finds the appropriate view for an item, if it exists. Something similar to this:
public View findViewAtPosition(int position) {
for (int i=0; i < listView.getChildCount(); i++) {
if (listView.getChildAt(i).getTag() == position) {
return(listView.getChildAt(i));
}
}
return(null);
}
I fixed it with an answer on another topic: https://stackoverflow.com/a/2679284/1352169
Áron Nemmondommegavezetéknevem's answer looks good, but this one is a little bit better since it e.g. keeps headers in mind too.
I'm trying to set a header and footer in my list view that are clickable buttons. The problem is that the OnClickListener isn't responding to anything and I can't figure out what I'm doing wrong.
$ View header = getLayoutInflater().inflate(R.layout.header_layout, null, true);
getListView().addHeaderView(header);
myAdapter = new myAdapter(this);
header.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Do what I want when i click it
}
});
Update
The best solution I ultimately came up with was adding a separate button to the header layout, and then doing it like this:
View header = getLayoutInflater().inflate(R.layout.header_layout, null);
Button headerButton = (Button)header.findViewById(R.id.header_button);
getListView().addHeaderView(header);
headerButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// My Click Stuff
}
});
You need to handle the click in the ListView's onItemClick. Simply check if that's the first or last item in the adapter and handle the clicks that way. You need to treat it as an item in the ListView.
I see a few issues:
when inflating the header, use getListView() as the second parameter (root, where you have null now)l
should the header be a View or a ViewGroup? I've ended up using ViewGroup in these situations.
finally -- perhaps you should be setting the click listener on the button in the header instead of the header itself?
There is a way more easier solution:
Just set a "OnClickListener" to the applied View:
View view = inflater.inflate(R.layout.xxx, null);
view.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View v) {
//do something
}
});
Very easy thing which solved it!
Example with a footer:
mYourListView.addFooterView(footer, null, true);
Then in the OnItemClickListener you can check:
#Override
public void onItemClick(AdapterView<?> parent,
View view, final int position, final long id) {
if (id != -1) {
// do whatever you do with list items
} else {
// do what you need after the footer been clicked
}
(If you need to handle and the header and the footer click, check position - 0 for the header and [adapter.getCount() - 1] for the footer)
This approach will provide the same visual effect while footer click as if the list item been clicked. (But if you do not need that effect just add OnClickListener to the footer and it will intercept all footer clicks)
i think the listview and buttons are fighting for focus and your listview is winning.
you'll have to use a onTouchListener for the buttons.
There is one more alternative and its to set the following on the footer. There is another method overload created but it did not come up in the docs, i had to check online documentation:
mylistView.addFooterView(footerView, null, false);
where false tells the footer its not selectable. I tested this myself and the buttons inside the footer respond to touches now. I hope this an acceptable answer.
What worked for me:
When inflating the header view, before adding it to the listview, I then used that view to get the subview and add a click listener on it
myHeaderView.findViewById(R.id.myButton).setOnClickListener(new OnClickListener() { ... } );
also, when I added it to the listView, I used the overloaded constructor with the third variable set to true
mListView.addHeaderView(myHeaderView, null, true);