OK, I have an app that needs access to basic swipe gestures. I've implemented a GestureDetector using code scraped from StackOverflow and then modified (to make it work at all). For it to work, it needs to steal Touch events.
Originally, I was detecting onScroll events and such and trying to pass them on to elements that needed to scroll, but this was really jumpy and never scrolled by the amount I wanted, so I started to simply pass the touch events on to the super-class after reading them. This caused really strange behavior and some elements never scrolled at all (no idea why), so I started passing events in a 3 way split ... some to the super-class, some to the gesture-detector, and some to the on-screen view that needed to scroll! Yeah, a mess, but everything is finally working smoothly. Except ...
If you touch the bottom of an EditText (it's full-screen except for the AppBar), then as the keyboard appears and scrolls the EditText up, the appbar scrolls off the screen (right under the statusbar icons ... looks weird because they overlay each other) and I can't make it scroll back. Also means I can't get to my Menu or the Cut/Copy icons. Hitting the menu key when it has scrolled off crashes the app.
Any idea how to stop the AppBar from scrolling off the screen?
#Override
public boolean dispatchTouchEvent(MotionEvent me) {
int top = dm.heightPixels - myEditText.getMeasuredHeight();
MotionEvent mod = MotionEvent.obtain(me.getDownTime(), me.getEventTime(),
me.getAction(), me.getX(), me.getY()-top, me.getMetaState());
if (me.getY() <= top)
return super.dispatchTouchEvent(me);
myEditText.onTouchEvent(mod);
return this.detector.onTouchEvent(me);
}
OK, this seems to fix it! In the activity manifest ...
android:windowSoftInputMode="adjustResize"
Bamn! No more problems!
Related
I have a horizontal slider in my app, and I want to make it so that if you have the slider selected, you can do the two-fingered swipe up or down gesture from anywhere on the screen (The scroll up or down gesture) to move the slider left or right. I haven't been able to find anything through google about how to change vertical swipe behavior for Talkback and was wondering if there was in fact a way to change this.
I'd really suggest not doing this, it isn't how Android works so it will confuse your users, and be a big source of bugs as any behavior like this can cause touch errors on completely separate views. I just fixed a problem on something similar in my company's app.
But if you really want to do this- your root ViewGroup needs to intercept touch events if there are two fingers down and it moves far enough to qualify. Read https://developer.android.com/training/gestures/viewgroup#intercept for an explanation of how a parent view group can steal touch events from the child. This is the same way ScrollView works to scroll its contents. In fact, looking up the AOSP implementation of ScrollView would give you good example code.
I have a bottom drawer - a view that is bottom aligned with the bottom of the screen and when dismissed animates itself down until it becomes invisible (in such state its top border is aligned with the bottom of the screen). I am trying to implement dismissing this view by vertical swipe down on it. To do it I attached a gesture detector in this method of the view:
#Override
public boolean onInterceptTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
I did it this way since this view contains a horizontal recycler view, so I do not want to intercept the child touches too early to make sure my view responds only to swipe down and does not steal horizontal touches from the recycler view (as described here: https://developer.android.com/training/gestures/viewgroup.html)
Now, my problem is that when I swipe on one area of this view, the fling recognition works, while when I swipe on another area ofthis view it does not work. In the first case I see in the debugger that onInterceptTouchEvent is called three times, the third call is recognized by the gesture recognizer as fling. In the second case I see that onInterceptTouchEvent is called only once.
It looks that some other view is stealing my touches, but I have no idea which one is that since my app is pretty complex and I am not the only author :). What is an easy way of debugging that in a general case? I would like to just know what view in the entire hierarchy of my activity consumed my event making onInterceptTouchEvent called only once - that would be a good start for the further investigation.
Thanks!
The way I do it is using emulator with android source code downloaded.
I put a breakpoint in View.dispatchTouchEvent (all places that returns true). This will show me which view is handling the event.
If this does not help, you can also place various breakpoint log messages.
I hope this will help you solve the problem :D
I have a problem which I am not sure how can I handle.
I started using a library called MenuDrawer on which I have given the following:
mDrawer.setTouchMode(MenuDrawer.TOUCH_MODE_FULLSCREEN);
Which allows it to pop open whenever I drag the screen down, but this actually rises another issue for me, because I use a ListView there that needs to be scrolled also.
I actually have 2 questions, taking in regards that not all may have used this library.
If you have used this library: Is it possible to focus the dragging on just 1 element? For example if I have a TextView there can I drag only that item to open the menu?
If you haven't used this library: How can a child element steal the focus from the parent on touch event? So that when I touch and drag somewhere where the listview is to achieve a successful scrolling up and down.
Right now I can scroll freely only down and when I try to scroll up opens the menu, unless I scroll the listview first down and up without breaking contact with the screen.
I found how to manage that. For me this simple piece of code worked like a charm:
mDrawer.setOnInterceptMoveEventListener(new OnInterceptMoveEventListener(){
#Override
public boolean isViewDraggable(View v, int dx, int x, int y) {
//v.getId();
if(y > 50){
return true;
}
return false;
}});
if anything below Y 50 is pulled it won't trigger the menu drawer.
I have a ScrollView which has two hidden images, one at the top and one at the bottom. In between there is a bunch of visible content.
What I need to do is make these images hidden by default but when you scroll all the way up or all the way down you could see them as you're scrolling. But then as soon as you stop scrolling it should bounce back to the visible area so that the hidden images aren't showing.
Basically I'm trying to imitate the bounce scrolling feature of the iphone UIScrollView.
I have my ScrollView all setup and I do a scroll at the beginning so as to hide the top hidden image. Now all I need to do is detect when a scrolling has ended, figure out the Y position, and check whether a hidden image is shown. If it is, I would just programmatically scroll the view back so that the hidden image is hidden.
I hope all that made sense.
So anyways, I know how to programmatically scroll a ScrollView. Now what I need is some sort of callback to tell me when a ScrollView ended scrolling and also a way to get the ScrollView's current 'Y' position. Are there any such methods I could use?
I looked through the ScrollView docs but nothing jumped out at me. I'm still not very familiar with the Android naming schemes so maybe I missed something obvious somewhere.
Anyways, any help would be appreciated here. Cheers.
You can use an OnTouchListener to detect when the user presses/releases the list.
You can also use the onScrollStateChanged method of the OnScrollListener class (most likely in conjunction with a touch listener) to detect changes in the SCROLL_STATE - when the list has stopped scrolling the state will change from a state that is not SCROLL_STATE_IDLE to SCROLL_STATE_IDLE.
Alternatively if you are using 2.3 or above you can use an OverScroller to get the desired effect (see Modifying Android OverScroll for how to change the over scroll effect to an iPhone like one).
Hello I am trying to make a terminal type app that is wider than the actual android screen. A listview is great except that I don't want the text to wrap. If the text is wider than the screen I want it to print the full text and then the user can scroll over horizontally if they want to see what was printed off the screen. Just FYI this is for ascii type tables. I have followed this example:
http://nan-technicalblog.blogspot.com/2008/12/android-how-to-use-horizontal-scrolling.html
It works great as far as horizontal text goes it does exactly what I want but I am unable to get the ListView inside the custom LinearLayout to actually scroll veritcally. I have tried passing the Y coordinates from the onScroll method to mListView such as:
mListView.scrollBy(0, distanceY);
but that seems to move the custom LinearLayout window instead of just scrolling the ListView. I can tell that the ListView is not scrolling because the window moves without the vertical scroll bar of the ListView moving. Everything just slides around. Any help would be much appreciated.
Okay this one also took me about a week in my spare time to figure out. I had to change the supplied code for dispatchTouchEvent to this:
public boolean dispatchTouchEvent(MotionEvent ev){
mGestureDetector.onTouchEvent(ev);
mListView.onTouchEvent(ev);
return true;
}
Also changed onScroll to return false just for good measure.