Android GridView setting certain item to nonClickable - android

I'm implementing a custom calendar using a GridView.
For this Calendar I have 3 view types, {DAY, TITLE, BLANK}
Is there a way to make certain items in a GridView not clickable?
What I'm trying to avoid is the press state animations for the items that aren't clickable. It ok it the user presses them, I can recognize that it's not the valid view in my onItemClickListener(). This is purely for UI purposes.

I found the solution. Don't know why I didn't search for ListViews in the first place.
You need to override the isEnabled() Function
Returning false will make it non-clickable. True will keep is clickable.
#Override
public boolean isEnabled(int position) {
switch(getItemViewType(position)) {
case CellTypes.BLANK:
case CellTypes.TITLE:
default :
return false;
case CellTypes.DAY:
return true;
}
}

In the adapter for your GridView, implement one of the get() method to return a reference to the object being clicked. I'm assuming that your adapter wraps a list of your "Calendar" objects.
In the onItemClickListener for your GridView, call get(index) or get(id) on the adapter to get a reference to the object being clicked. Check its type to see if it is one that you do not wish to be clickable, and return before executing the logic that is usually called when a clickable item is clicked.

In XML: android:clickable="false" and in code: setClickable(false);

Related

Android: Detect if a ListView has the scrollbar (after setting new data)

I have an ArrayAdapter linked to a ListView.
mListView.setAdapter(mArrayAdapter);
Whenever I reset the ArrayList data to the ArrayAdapter:
mArrayAdapter.clear();
mArrayAdapter.addAll(mArrayList);
mArrayAdapter.notifyDataSetChanged()
the ListView gets correctly updated
however, if just after the above three lines, I call my custom method mListView.hasScrollbar() to detect whether the listview has a scrollbar or not, I get a null lastVisibleItem:
public boolean hasScrollbar() {
View lastVisibleItem = (View) getChildAt(getChildCount() - 1);
if (lastVisibleItem.getBottom()>=getHeight()) {
return true;
}
return false;
}
does it mean that the listview is still refreshing?
My main question is:
how can I test if the listview has the scrollbar after resetting the adapter with new data?
thank you for any help!
Using getLastVisiblePosition / getFirstVisiblePosition is a valid method of detecting wether you have scrolling or not within the list view (aslong as you compare it to getCount() and do your math ofc).
The problem you have as you already guess is that you are attempting to check out of sync.
In order to sync your query when the adapter already filled your List Data and updated changes, you need to issue a post request to the list, which will stack that petition to the message queue of the adapter.
yourAdapter.notifyDataSetChanged();
yourAdapter.getListView().post(new Runnable() {
#Override public void run() {
//your code here
}
});
Make sure to call that after notifySetDataChanged() of course. Because you want the list to update before the check.
I think your question equals to "how to tell if list view contains items need to displayed on more than one screen"?
So my suggestion is to use listView.getFirstVisiblePosition() and getLastVisiblePosition() to tell it.

how to access ListView with CheckedTextView?

I'm now developing an application that uses a ListView with a
CheckedTextView on every item that managed by an ArrayAdapter to
support multiple chooses. The contents in my ListView are dynamic, that
means, can be changed during runtime. Now I try to use
ListView.getCheckedItemPositions() to get all checked items, Because I want
to save all the checked positions and auto-check them when user go back to
this page again. So I need to save checked results for every page.
For the first page everything works fine as expected. But when user goes to
another page and make some chooses, the result array that ListView returned
contains some positions that are never checked. I don't why ListView has
this strange behavior. Even for a page that in fact no checked happens but
ListView gives me a result that indicates there's one item has been checked.
could anyone who can teach me how to get the position of CheckedTextView
in its OnClickListener callback?
example code is appreciate.
Thanks in advance...
The listview recycles its views so when you go to a different page and then return to the previous page, the listview recalls the getView() function for its views. To make sure that the order of the checked views are not mixed up, create an arraylist that contains the check state of all the views before initializing the adapter. Then pass the arraylist as an argument for the adapter's constructor. There, in the getView() function, set the checked state of each checkable textview based on the arraylist. Then, return to the activity class and override the onItemClick() event. Using the view that is given to you when the function is called, do the following to get the checkable textview and set its checked state:
listView1.setOnItemClickListener(new OnItemClickListener()
{
#Override
public void onItemClick(AdapterView<?> arg0, View selectedView, int position , long id)
{
CheckedTextView tv = (CheckedTextView)selectedView.findViewById(R.id.textview);
if (tv.isChecked())
{
tv.setChecked(false);
checkStatesOfViews.get(position) = false;
}
else
{
tv.setChecked(true);
checkStatesOfViews.get(position) = true;
}
}
});

ListView item backgrounds not changing

I have an unusual issue with my ListView. I currently have a "deselectAll()" method which iterates through the items in my ListView and sets them to unchecked (the items implement the Checkable interface). The "checked" variable gets changed correctly (the view reports as not being checked), but the visual indicator (in this case, a background change) does not show the view as unchecked (the background stays the color of a checked item).
I am iterating and deselecting through my listview like so (I also added my declerations):
private ListView vw_entryList;
private void deselectAll() {
for (int i = 0; i < sAdapter.getCount(); i++) {
((Entry)vw_entryList.getItemAtPosition(i)).setChecked(false);
}
}
The code for my implemented setChecked() is as follows:
public void setChecked(boolean checked) {
_checked = checked;
if (checked) {
setBackgroundResource(R.drawable.listview_checked);
}
else {
setBackgroundResource(R.drawable.listview_unchecked);
}
invalidate();
}
It should be noted that when the items are clicked, they are toggled between checked and unchecked in the OnItemClickListener, and this works ok, with the background change and everything. The code for toggling is very similar:
public void toggle() {
_checked = !_checked;
setBackgroundResource(_checked ?
R.drawable.listview_checked : R.drawable.listview_unchecked);
invalidate();
}
The only difference I can see is where the methods are called from. toggle() is called from within the OnItemClickListener.onClick() method, while my deselectAll() is called from within a button's standard OnClickListener, both in the same class. Does anyone have any ideas as to why the background doesn't change when I call my deselectAll() function?
Do you have custom, non-standard color for the background? If so you might take a look at http://www.curious-creature.org/2008/12/22/why-is-my-list-black-an-android-optimization/ - it boils down to setting android:cacheColorHint attribute of your list to the background color. Maybe that will help.
Edited after further discussion:
I think you need to call getAdapter().notifyDataSetChanged() on the List rather than invalidate(). List is really build in the way that it is relying on adapter to provide the data. What you are doing in fact you have an implicit adapter - Entry is really kept in the adapter and by setting checked, you are changing the data model really, but if you do not call notifyDataSetChanged() the list does not really know that the model has changed and will not recreate the views (invalidate() will only redraw the existing ones).
After trying everything (thanks for your help Jarek), I found a solution that works for my purposes. Instead of implicitly calling the setChecked() within the view that was clicked, I leave it up to the setItemChecked() method within the ListView class.
My updated code:
private void deselectAll() {
for (int i = 0; i < sAdapter.getCount(); i++) {
vw_entryList.setItemChecked(i, false);
}
}
My best guess is that the ListView knows that its items implement the Checkable class, and thus requires itself to be the handler of all item operations. Something along those lines. If anyone can explain in more detail why this solution works while the others did not, I'll reward them with the answer and an upvote.

handle onlongclicklistener of menus

I need to handle the selected row in listview on long click on the row but because am using menus I can't override the onclicklistener. I am trying to do this:
listView.setOnLongClickListener(new OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
taskPosition = listView.getSelectedItemPosition();
return true;
}
});
but it doesn't work. Can anyone help me?
i got the value of listView.getSelectedItemPosition(); is equal -1
Of course. Rows typically are not selected. Rows are only selected if the user is using a pointing device (D-pad, trackball, etc.).
i need to handle the selection longclick on listview and use it in onContextItemSelected to perform action
No, you don't. You either use context menus or you use a long-click listener with a widget. You do not use both.
If you are trying to determine what row was long-clicked from onContextItemSelected(), here is a sample project that will demonstrate that for you, if your adapter is an ArrayAdapter. If you are using a CursorAdapter, here is a different sample project that will demonstrate this for you.

How to use setMultiChoiceItems() with a Custom AlertDialog that uses an efficiency arrayadapter?

I am writing a music player that uses a custom Adapter extending BaseAdapter (efficiency adapter) that I want to display in an AlertDialog using setAdapter() where the user can either click on one of the songs to switch to that position in the playlist OR check songs to remove from the playlist. I tried using a custom click listener so that a user could just long click to remove the item from the list but the listview just doesn't work right... it was removing the wrong items (the ones at the end) even though the ArrayList contained the correct playlist items... (when I removed the item from the ArrayList, I passed it to the adapter which called notifyDataSetChanged... but that just didn't work as I mentioned. There is definitely a bug in the AlertDialog ListView... because there is no reason for it to have popped off the results from the end rather than the correct item.
So... the next method I would like to try is to use the setMultiChoiceItems() method of the AlertDialog... but it appears that it doesn't work with a custom adapter... only simple arrays. Will I have to subclass AlertDialog and Override the setMultiChoiceItems() method or is there a way I can make it work with an ArrayAdapter?
Basically, I can't figure out how to even iterate the list that the AlertDialog creates or whether it even passes that view somehow. In addition, I don't think I can even listen to clicks on checkboxes if I add those to the row. Any help will be greatly appreciated.
EDIT: Asking questions here is like magic... I answered my own question... this is how I did it. I added a hint to each checkbox which is the position of the item in the ArrayList. Then I used OnCheckedChangeListener to capture the selections. When you set a hint it adds text to the checkbox... since the background of the AlertDialog is white (even for clicked items?) I just set the hint text color to transparent.
holder.check.setHintTextColor(Color.TRANSPARENT);
holder.check.setHint(String.valueOf(position));
holder.check.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
int position = Integer.parseInt((String) buttonView.getHint());
Log.v("onCheckedChanged", "Checked: "+isChecked+" returned: "+position+" which should be "+getItem(position).name);
}
});
Refer This and This
then
Pass a reference to byte[] in setMultiChoiceItems().
final boolean[] booleans = {false, true, false, true, false, false, false};
Then check the value of booleans inside setPositiveButton().
If you need to pass this AlertDialog around, then extend AlertDialog and have create a field boolean as described in 1.

Categories

Resources