I've got a ListActivity that displays WebViews.
There is a menu option to copy text that will call this on visible WebViews.
Everything works except for one thing. I can't perform text selection in vertical direction as ListView consumes corresponding MotionEvents for it's own scrolling.
I've tried this:
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (webViewsInTextSelectionMode) {
bypassEventToWebViews(ev);
return true;
} else {
return super.dispatchTouchEvent(ev);
}
}
Which will block scrolling but will also pass unadjusted MotionEvent coordinates to a WebView.
Is there a way to correctly prevent ListView from scrolling in this case?
I've got a ListActivity that displays WebViews.
That is not a good idea. WebView and ListView will compete for motion events. Putting scrolling things in scrolling things is rarely advisable in Android, particularly when they can scroll in the same direction (in this case, up and down).
There is a menu option to copy text that will call this on visible WebViews.
If you mean the accepted answer on that question, that is also not a good idea. I am dubious about the other answer, but at least it's not a bad idea prima facia.
Everything works except for one thing. I can't perform text selection in vertical direction as ListView consumes corresponding MotionEvents for it's own scrolling.
My point exactly.
Is there a way to correctly prevent ListView from scrolling in this case?
I would focus instead on getting rid of the WebViews, replacing them with TextView and Html.fromHtml(). Or, get rid of the ListView, using a single WebView to render your consolidated content.
This is a complete shot in the dark and most likely won't work but probably worth a try. You can try calling ViewParent#requestDisallowInterceptTouchEvent on the parent ListView inside of the ViewGroup containing your WebView. You'll have to call that every time there is a down motion event for the duration of the text selection. This is because the flag is reset on a up/cancel motion event.
If that doesn't work you'll probably have to create your own copy of ListView and modify it appropriately. This isn't too daunting, you'll have to copy all classes in the class hierarchy back to AdapterView and fix the copied AdapterView class (mainly use of private/package level member variables that have protected/public accessors functions).
Related
My problem is on two fronts.
First issue: Scrolling amnesia
I have a ListView with spinners and edit texts. It acquires it's data from webservice. The problem is when I write up a value on the EditText or select something for the spinners and scroll them out of view. When I come back the fields are empty and the spinners are again in their default selection.
Attempted solution
I have tried resolving the issue by setting ScrollingCacheEnabled programmatic and within the AXML file to both true and false just to see if that is an issue. It seems not to have any kind of an effect.
Second issue: Focus Loss
When I touch the EditText within this same ListView I get the keyboard to appear but I loose the focus on the field and it needs to get touched again to get focus and it allows me to be written.
Attempted solution
I fiddled with setting the fields focusable, Focusavle in toucmode, touchable and whatnot but came out empty handed.
Honestly I am quite new to android and to programming on this level as well but I tried my best on this. I might have just missed something due to lack of knowledge or it's just something somebody with more experience could tackle and solve.
The second issue isn't that bad for now (still after filling out quite a number of fields it does get tiring to set it twice...) but the scrolling issue is a must.
I think you problem relates to that you forget to update the items in the Adapters when you alter the Views containing them. So you need to wire up the events from the Views to update the items.
Why? If you look carefully at your Adapter for you ListView you populate the convertView with the values of GetItem(position). So if that item does not reflect the changes you have made to the View you are bound to get the initial values of that item.
So what you need to do is to hook up SpinnerValue.ItemSelected and all the other Views which can be altered events, so that the items in the Adapter get their values updated. Remember to only add event handlers when you first create the View. So that is when convertView is null.
Also consider changing the lines:
if (SpinnerValue.Adapter.Count.Equals(2))
{
SpinnerValue.SetSelection(1);
}
To be based on the items in the Adapter rather than setting it to 1 every time.
You focus problem is based in that ListView is not really made for having Views inside of it wanting the focus. Try setting the ListView DecendantFocusability when you instantiate it to DescendantFocusability.AfterDescendants like so:
lstPrevzem.DescendantFocusability = DescendantFocusability.AfterDescendants;
I resolved the issue by replacing the listview with LinearLayout and pinning the adapter to it. The "fixed" code is available on pastebin.
Fixed code:
http://pastebin.com/vn3SPrFz
I'm trying to show an animation with all Views that I've created from an adapter. When I scroll down, it shows the animation correctly, but when I scroll up, I see these Views recreate themselves and show the animation again. Then, when I scroll down, it happens again.
My assumption is that the mechanism of creating a View from an adapter is to load the View into memory; just the group of Views which are on screen right now (but above and below views are not loaded into memory). These will be loaded again when I scroll to these views, right?
Is there any way to fix this problem?
PS: Sorry for my English, I hope you understand my problem.
My assumption is that the mechanism of creating a View from an adapter
is to load the View into memory; just the group of Views which are on
screen right now (but above and below views are not loaded into
memory)
That's somewhat correct: a ListView will not try to visualize any data that isn't (at least partially) visible. It also 'recycles' views, meaning that any view that isn't currently used to present data to the user and is of the same 'type' as the next data item, may get reused.
Hence you shouldn't rely on persisting data with or make any assumptions about the existence of particular views. In stead, use something that's separate from the views; e.g. the dataset you're visualizing.
Quite often, you'll supply a list of POJOs to a BaseAdapter or ArrayAdapter. You could simply add a boolean to the POJO indicating whether it should animate or not, and change that whenever the animation for that particular item finishes. Alternatively, you could keep track of these values in a separate collection (which is probably the more straightforward approach if you're dealing with a Cursor as data source rather than POJOs).
I know it's somehow possible to make a ListView that loads more data when the user has reached the bottom of the list. However, I'm working with a ScrollView, which I have a LinearLayout in, and these two components works great with the scrolling and so. But I don't know how I'm supposed to do so it gets an infinite scroll.
I suppose I need to add something that reads what is shown of the LinearLayout on the screen, and when it calculates that it is the bottom of the LinearLayout that is being shown (by using the current position and the height of the View), it triggers an event.
But as I said, I don't know how to accomplish this. So, if anyone can give me some help I would be very grateful.
EDIT: I found this post here on StackOverflow How to trigger an event when scrollView reach the bottom with Android?, but I don't know what to do with the answer:
Given the requirements, you'll likely be extending BaseAdapter (as opposed to CursorAdapter which utilizes a different mechanism).
Here's a snippet for that:
public View getView(int position, View convertView, ViewGroup parent) {
if (position == backingLinkedList.size()) {
//get more items and add them to the backingLinkedList in a background thread
notifyDataSetChanged();
}
}
If you can trigger an event when you reach the bottom of a scrollview, You could try creating your own type of view to hold your data. When you reach the bottom of the view load the next data into your view class and add it into the layout of the scroll view.
So basically create a class that holds a section of what your showing. Add the first one into the scrollview. When you hit the bottom create another view holding your next data and use scrollviews_layout.addview(view_holding_the_new_data)
I know this was solved a long time ago, but I wanted to share my solution for future infinite scrollers.
I used the onScroll method within the OnScrollListener to trigger a background thread to grab more data and adapter.notifyDataSetChanged to notify the ListView of more data to load and create an infinite scroll. For some reason, onScrollStateChanged wasn't triggering, but onScroll did what I needed so I didn't need to bother.
For the longest time I didn't understand how to keep the ListView from reloading and placing me back at the top of the list, but then I realized I only need to initialize a new adapter and call setListAdapter once, and every time after that, only call notifyDataSetChanged. Before, I was also calling setListAdapter, thereby placing me back at the top.
lets assume i have a LinearLayout , horizontal that contains a TextView and afterward a Spinner or another clicable TextView or an EditText.
I want that a click on any part of the line (if the layout has padding then the layout area as well!) will deleage the onTouchEvent to the Right part of the layout (EditText, TextView or Spinner) as if they were clicked themselves.
Doing it myself will require me either create my own versions of those widgets (too much work for little effect :-( ) or putting listeners on many items for the touch events and delegate them. I'm pretty sure Android has some methods or properties to do that, just didn't see any so far.
Can anyone help ?
I had to do something similar to this a while back, and ended up writing my own delegate and assigning the onclicklisteners for all of the components in my layout to that delegate. It's cumbersome, but not too painful to implement, and it turned out well.
Point being, I didn't see anything in the API to handle that sort of thing. The only other thing I might offer is that it is certainly possible to assign an onclicklistener to a component and simply send the event to another component's onclicklistener like so:
thislinearlayout.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getOtherComponent().performClick();
}
});
You can do the same thing with touch listeners.
Is it possible to apply an expand or collapse animation for expandableListView?
It can be done using a simple ListView that contains an initially hidden view and a custom class that extends Animation.
The basic idea is to start with View.GONE then gradually re-size the margin from a negative value to the required size while setting visibility to View.VISIBLE.
See:
https://github.com/tjerkw/Android-SlideExpandableListView
Android Animation: Hide/Show Menu
How do I animate View.setVisibility(GONE)
..and finally
Cool toolbar for ListView items + source
The last example contains all the code you need. It looks a bit hackish to me, especially the fact that you must initially set view.bottomMargin = -50 or more, otherwise the animation does not work properly the first time, but so far I did not find any viable alternative (apart from using a ScrollView with your own container items instead of a ListView).
And finally, this app includes the above example, among lots of other useful examples with links to sources:
https://market.android.com/details?id=com.groidify.uipatterns
Update: Google removed the app from play store allegedly for intellectual property violation (although it only contained demos and links to open source projects), the author now made the apk available for direct download from http://goo.gl/ihcgs
For more details see https://plus.google.com/108176685096570584154/posts. NB: I'm not affiliated with the author.
I have done a similar job for a simple list view.For doing that I overrode the getView method and applied translate up( or down) animation on each list item.The degree of translation was decided by the position of the list item.
I've found a possible (partial) workaround for this problem.
first you need to store the scroll state of the ExpnadableListView :
#Override
public void onScrollStateChanged(final AbsListView view, final int scrollState) {
this.mScrollState = scrollState;
}
public int getScrollState() {
return this.mScrollState;
}
for the listView itself, you need to store which group was clicked, so that only its children will get animated:
mListView.setOnGroupClickListener(...
#Override
public boolean onGroupClick(...){
mGroupPosition=groupPosition;
now, in the getChildView() method, you check the state of the scrolling , and if it's idle, you start the animation, for example:
public View getChildView(...) {
// <=prepare rootView and return it later
if (groupPosition==mGroupPosition&&getScrollState() == OnScrollListener.SCROLL_STATE_IDLE)
rootView.setAnimation(...)
this will set an animation for the child views each time you expand the group.
the drawback of this are:
only for the expanded child views. you will need to think of extra logic to animate them when collapsing the group.
all animations start at once . you will need to add multiple animations one after another if you wish that it would work otherwise.