I've got a class that extends EditText and overwrites the onTouchEvent()-method in order to see when the corresponding MotionEvents occur:
public class CustomEditText extends EditText {
public CustomEditText(Context context) {
super(context);
}
public CustomEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomEditText(Context context, AttributeSet attrs, int i) {
super(context, attrs, i);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN: Log.v("ME", "down");
break;
case MotionEvent.ACTION_UP: Log.v("ME", "up");
break;
case MotionEvent.ACTION_MOVE: Log.v("ME", "move");
break;
case MotionEvent.ACTION_CANCEL: Log.v("ME", "cancel");
break;
}
return true;
}
}
When the View isn't inside a ScrollView, everything works as expected: LogCat prints "move" as long as my finger is moving around on the screen.
But when the View is inside a ScrollView and I'm moving my finger vertically, LogCat prints some "move", after a couple of millimeters a "cancel" and then nothing anymore until I replace my finger on the screen. This doesn't happen when I move horizontally.
I think the reason is that at this point the ScrollView recognizes that it should start scrolling now and consequently "steals" the MotionEvents from the View in order to evaluate them itself.
My question is now: How can I prohibit this behaviour without creating a new class extending ScrollView?
Thanking you in anticipation
Daniel R.
Why don't you try to setOnTouchListener
ex:
ScrollView yourScrollView;
yourScrollView.setOnTouchListener(new View.OnTouchListener(){
public boolean onTouch (View v, MotionEvent event){
yourTextView.onTouch(yourTextView,event);
}
});
something in these lines.. please report back so I could edit the answer to the best
(It's me, DanielR. I've now got my own account, sorry for that.)
Thanks a lot for the rapid answer, Sherif. That solves my problem.
What I am actually doing in my app is viewing a scrollable EditText that has 3 areas: a small margin on the left and the right in which you can scroll the View and a main area in the centre in which the common editing actions are performed.
What I am doing to achieve this, is:
1. when the user starts a gesture in the margins, I set the onTouchListener to null, so the ScrollView's scrolling action is performed (read that in a post somewhere around here).
2. touching the main area, the onTouchListener is set to the one you suggested above, so scrolling is disabled AND all touch events reach the EditText. Previously, my onTouchListener was empty so merely scrolling was prohibited. I don't know why I didn't see that myself. I think it's just too late ;)
Once again, thank you a lot.
Related
I want to make a view like
Sample image
in which a want to show google maps inside a bottom sheet fragment.
What I've tried
I've tried to show maps inside a bottom sheet dialog fragment but the output isn't what I desire.
What I require is a fixed size view which should be able to display maps. Currently my view is also responding to user gestures to change bottom sheet state but I require gestures to work on map only (e.g for map panning).
When we use the map on BottomSheet, it conflicts touch events. So, need to disallow touch of BottomSheet.
Please find a below custom class which allows the map to move.
public class BottomSheetMapView extends MapView {
public BottomSheetMapView(Context context) {
super(context);
}
public BottomSheetMapView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BottomSheetMapView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public BottomSheetMapView(Context context, MapboxMapOptions options) {
super(context, options);
}
#Override
public boolean onInterceptTouchEvent(final MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_UP:
getParent().requestDisallowInterceptTouchEvent(false);
break;
default:
break;
}
return super.onInterceptTouchEvent(event);
}
}
I am using Mapbox. So, I use com.example.BottomSheetMapView instead of com.mapbox.mapboxsdk.maps.MapView in xml. Similarly, you can use Google map.
This satisfies your requirement.
I need to implement the same feature. In my case, I used a BottomSheetDialogFragment that contains SupportMapFragment. The problem was, I could only make horizontal gestures on the map like panning it, but not vertical gestures. What needs to be done is to disable the BottomSheet's touch listener while the user is doing some gestures on the map. You can refer to my similar post here to see how it should be done https://stackoverflow.com/a/53740355/1767167
I am using a ViewPager with a TouchImageView inside it and it works great, (I have used this solution in many of my Android apps).
However I have an app for which there are many other controls on the same screen so they are all inside a scrollview control.
In this scenario I see the scrollview does not play nice and I am not able to pan within the zoomed image. When I use my finger to pan upward or downward the entire page scrolls instead of the image panning.
So here is what I am trying to do....
Inside the TouchImageView I detect Zoom Begin and Zoom End and have created an interface to make a callback to my Activity onZoomBegin() and onZoomEnd() methods.
In the onZoomBegin() method I want to disable the scrollview from responding to any touch events and in onZoomEnd() I can re-enable it.
So far here are the things I have tried doing in the onZoomBegin() method for which none are working....
scrollView.setEnabled(false);
scrollView.requestDisallowInterceptTouchEvent(true);
also I have tried the answer to a similar question which was to takeover the onTouchListener like such:
scrollView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
This does stop the scrollview from scrolling but the scrollview is still intercepting the touch events cause the image still will not pan up or down.
I've tried checking nestedScrollingEnabled in the layout designer, no joy....
I just want to know is there a way to totally disable a scrollview and then re-enable it from responding to touch events?
I found this answer on another question somewhere but by the time I realized it was the solution to my problem (answer to my question) then I lost reference to it. I will keep looking so I can edit this post to give credit where credit is due.
public class CustomScrollView extends ScrollView {
// true if we can scroll the ScrollView
// false if we cannot scroll
private boolean scrollable = true;
public CustomScrollView(Context context) {
super(context);
}
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setScrollingEnabled(boolean scrollable) {
this.scrollable = scrollable;
}
public boolean isScrollable() {
return scrollable;
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// if we can scroll pass the event to the superclass
if (scrollable)
return super.onTouchEvent(ev);
// only continue to handle the touch event if scrolling enabled
return false; // scrollable is always false at this point
default:
return super.onTouchEvent(ev);
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// Don't do anything with intercepted touch events if
// we are not scrollable
if (!scrollable)
return false;
else
return super.onInterceptTouchEvent(ev);
}
}
This part I just figured out for myself.... In the TouchImageView I added a callback interface which is called when a zoom begins and ends so in my Activity I only had to do this:
private class OnZoomListener implements TouchImageView.OnZoomListener {
#Override
public void onZoomBegin() {
isZoomed = true;
scrollView.scrollTo(0, 0);
scrollView.setScrollingEnabled(false); // <-- disables scrollview
hideImageControls();
sizeViewPager();
}
#Override
public void onZoomEnd() {
scrollView.setScrollingEnabled(true); // <-- enables scrollview
showImageControls();
isZoomed = false;
}
}
My overall goal is to be able of dragging a row from the RecyclerView to another view inside my app.
With a standard RecyclerView with LinearLayoutmanager and no extra mumbo-jumbo my drag-and-drop operations work flawlessly. However, as soon as I introduce a custom library called AndroidSwipeLayout to make each row swipeable to reveal extra actions everything fails and I get the common error:
08-28 09:59:03.465: I/ViewRootImpl(15310): Reporting drop result: false
Also I can see that the only DragEvents that are fired on my receiving view are ACTION_DRAG_STARTED and ACTION_DRAG_ENDED, all other events are skipped. As you can see I am returning true from ACTION_DRAG_STARTED but that doesn't help, my thought is that the custom library somehow eats my event. But I can't pinpoint where.
Here is my OnDragListener:
private class MyDropListener implements View.OnDragListener {
#Override
public boolean onDrag(View v, DragEvent event) {
// Doing some calculations based on event x and y. Not related to the problem.
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
// Some unrelated code, updating how views are displayed
return true;
case DragEvent.ACTION_DRAG_LOCATION:
// Some unrelated code, updating how views are displayed
return true;
case DragEvent.ACTION_DROP:
// Some unrelated code, updating some data and updating how views are displayed
return true;
case DragEvent.ACTION_DRAG_ENDED:
// Some unrelated code, updating how views are displayed
return true;
case DragEvent.ACTION_DRAG_ENTERED:
// Some unrelated code, updating how views are displayed
return true;
case DragEvent.ACTION_DRAG_EXITED:
// Some unrelated code, updating how views are displayed
return true;
default:
return false;
}
}
}
I've experimented now for a few days inside the library but can't find a solid solution exactly where my event dies. Sometimes I've managed to get the drop working, but it's very irregular behaviour.
I've also made a Github issue for this problem:
AndroidSwipeLayout - issue #211
I'm sure this is not specific to this library, but a problem when there's too much gesture detection going on for each view in a list. The library is really excellent I think and I don't wish to write that interaction myself.
Any thoughts, or comments, are welcome and appreciated. Even if you don't know the exact solution.
Thanks.
This was actually not caused by the library, or the listeners, it was caused by an EditText that was located in the same layout.
It was solved by creating a new class that subclasses EditText and ignores the dragEvent.
public class EditTextNoDrag extends EditText {
public EditTextNoDrag(Context context) {
super(context);
}
public EditTextNoDrag(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextNoDrag(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public EditTextNoDrag(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public boolean onDragEvent(DragEvent event) {
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
return false;
default:
return super.onDragEvent(event);
}
}
}
You can also toggle the focusable of the EditText on and off.
See this related isseu: Prevent drag drop of custom mimetype to EditText
I have a TextView inside a ScrollView I want to be able to change the font of the TextView whenever the user pinches it. I've been searching for a day now and I didn't find anything satisfactory. While I was hopping this to be pretty straightforward. Do you have any suggestions?
Ok, first implement pinch to zoom in TextView, you can get some idea from here and then as according to the scale value of user pinch try to set textSize of TextView. After that immediate disable touch event of ScrollView when user pinch or touch to the TextView. You can do that in this way(Just use variable instead of true/false return):
public class InterceptScrollView extends ScrollView {
public InterceptScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
}
and when user done with TextView then again enable the touch event of ScrollView.
Anyone please help me on this.
I action to be done here is, when X axis ranges on graph 1(accuracy) is zoomed, the same ranges also be reflected on graph 2(latency).
In clear,
When we are zooming the ranges 2,4,6,8,10 will be changed to 1,2,3,4,5.
When this changes happen on graph 1, the same ranges should be displayed on graph 2 also.
How I can achieve this.
I have tried using following way:
Analysed the scenario to find the way to trigger event in 'Accuracy View' chart when we do some action in 'Latency View' chart (and vice versa).
Written a code to trigger an event using dispatchOnTouch function. Unfortunately, dispatchOnTouch is not executing the event.
Investigated the issue in dispatchOnTouch function and found that OnTouchEvent on ControllerView class is ignoring the new event.
Thanks in Adavance!
I'm not using the same library as you (I use androidplot) but I achieve this by creating my own class which extends the plot class of the library and implements OnTouchListener. I also defined a slavePlot variable in my class. The 1st plot is the slave of the 2nd and vice versa. Then when an action is made on one plot, you can do the same on the other.
public class MyXYPlot extends XYPlot implements OnTouchListener {
private MyXYPlot slavePlot;
public MyXYPlot(Context context, AttributeSet attributes)
{
super(context, attributes);
this.setOnTouchListener(this);
}
public void setSlavePlot(MyXYPlot theplot)
{
this.slavePlot = theplot;
}
public boolean onTouch(View view, MotionEvent motionEvent) {
switch(motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: //start gesture
break;
case MotionEvent.ACTION_POINTER_DOWN: //second finger
break;
case MotionEvent.ACTION_POINTER_UP: //end zoom
break;
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
}
Hope this help!