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.
Related
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;
}
}
I have a Webview that is embedded inside a scrollview. The Webview itself has areas that are vertical scrollable.
Now if I try to scroll inside the webview, the scrollview intercepts the touchevent and scrolls the whole webview instead that only the small scrollable div is moved.
How can I make the scrollview work only if the webview does not want to scroll?
#Janusz, I have had the same problem. My solution is based on the extended scroll view behaviour in couple with the correct layout. I have wrote the answer to the same question here.
Let me know in case you have implementation problems or questions and, please inform whether it helps :)
In my case, I have a webview within a scrollview container, and the scrollview and webview are full screen. I was able to fix this by overriding the onTouch event in my webView touchListener.
scrollView = (ScrollView)findViewById(R.id.scrollview);
webView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
scrollView.requestDisallowInterceptTouchEvent(true);
return false;
}
}
Use TouchyWebView.java
public class TouchyWebView extends WebView {
public TouchyWebView(Context context) {
super(context);
}
public TouchyWebView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchyWebView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
public boolean onTouchEvent(MotionEvent event){
requestDisallowInterceptTouchEvent(true);
return super.onTouchEvent(event);
}
}
In layout file:
<yourclasapath.TouchyWebView
android:id="#+id/description_web"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
Our solution uses a Javascript callback through the Javascript Interface. Every time a part of the UI that is scrollable inside the WebView is touched a listener is called through java script and this listener calls requestDisallowInterceptTouchEvent on the WebViews parent.
This is not optimal but the nicest solution found at the moment. If the user scrolls very fast the layer in the WebView won't scroll but at a normal scroll rate it works fine.
edited for clarity
I feel like this question already has an answer, but I can't find one.
I have a ScrollView in my layout, and it contains a variety of clickable views.
Under a specific condition I would like to disable clicks and events for the ScrollView and ALL of its children.
The following have not been helpful:
ScrollView.setEnabled(false)
ScrollView.setClickable(false)
ScrollView.setOnTouchListener(null)
As well as:
(parent view of the ScrollView).requestDisallowInterceptTouchEvent()
I have created a custom ScrollView with the following code:
public class StoppableScrollView extends ScrollView
{
private static boolean stopped = false;
public StoppableScrollView(Context context)
{
super(context);
}
public StoppableScrollView(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
if(stopped)
{
return true;
}
else
{
super.onInterceptTouchEvent(ev);
return false;
}
}
#Override
public boolean onTouchEvent(MotionEvent ev)
{
if(stopped)
{
return true;
}
else
{
super.onTouchEvent(ev);
return false;
}
}
public static void setStopped(boolean inBool)
{
stopped = inBool;
}
public static boolean getStopped()
{
return stopped;
}
}
Using only onTouchEvent() will stop the scrolling, but not the clicking of child views.
Using only onInterceptTouchEvent() makes it such that when clicks work scrolling does not, and vice versa.
Using both onTouchEvent() and onInterceptTouchEvent() successfully stops unwanted clicks on child views when stopped is 'true' but it also disables scrolling regardless of the state of stopped.
Is there an easier way to get this behaviour, or is there a way to modify the StoppableScrollView class so that it will handle these touch events properly?
What probably should help is the following (because I had similar problems):
In the ScrollView you should do a RelativeLayout as Main Child (ScrollView does accept only 1 main child anyway). This RelativeLayout should of course of fill_parent in both directions.
At the really end of the RelativeLayout (after all other children), you could put now a LinearLayout with transparent background (#00FFFFFF) which has also fill_parent in both directions. This LinearLayout should have Visibility = View.GONE (by default)
Also you have to attach an empty OnClickListener to it. Now, because of zOrder if you make this LinearLayout Visibility = View.Visible it will catch all the events and avoid clicking the children above!
As scrollview allows immeditate one child say in my case i have linear layout.and in this linear layout i have other conreolls.
now our first task is to get this linear layout so what we can write is
LinearLayout l = (LinearLayout) scrollview.getChildAt(0);
now after getting this linear layour we can easily access other controlls placed inside it via this code and disable it.
for(int i =0; i<l.getChildCount(); i++)
{
Log.i(TAG,"child "+ l.getChildAt(i));
l.getChildAt(i).setEnabled(false);
}
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.
I have a ListView where each row has two webviews side by side, taking up the entire row. I've set up onListItemClick() in my ListActivity, but they are not fired when I tap on one of the rows (unless the place I happen to tap is outside the webview's border - but this isn't likely behavior, users would most likely want to tap on the image inside the webview).
I've tried setting setFocusable(false) and setFocusableInTouchMode(false), but those don't help.
Ideally this would operate exactly like Facebook's newsfeed, where you can tap on the profile picture of someone's wall post and it acts as if you've tapped the entire row (in FBs case the text for the wall post)
Figured it out, posting my solution in case someone else wants to do something similar:
I had to use an OnTouchListener, since OnClick and OnFocus weren't working. I extended a class that is reuseable:
private class WebViewClickListener implements View.OnTouchListener {
private int position;
private ViewGroup vg;
private WebView wv;
public WebViewClickListener(WebView wv, ViewGroup vg, int position) {
this.vg = vg;
this.position = position;
this.wv = wv;
}
public boolean onTouch(View v, MotionEvent event) {
int action = event.getAction();
switch (action) {
case MotionEvent.ACTION_CANCEL:
return true;
case MotionEvent.ACTION_UP:
sendClick();
return true;
}
return false;
}
public void sendClick() {
ListView lv = (ListView) vg;
lv.performItemClick(wv, position, 0);
}
}
The sendClick method could be overridden to do what's needed in your specific case. Use case:
WebView image = (WebView) findViewById(R.id.myImage);
image.setOnTouchListener(new WebViewClickListener(image, parent, position));
I managed to get this working with the following:
class NoClickWebView extends WebView {
public NoClickWebView(Context context) {
super(context);
setClickable(false);
setLongClickable(false);
setFocusable(false);
setFocusableInTouchMode(false);
}
}
You can use this class or just set these properties on a standard WebView.
Got it working in Android 4.4 using the same approach as bjdodson above but also overriding dispatchTouchEvent
public class NonClickableWebview extends WebView {
public NonClickableWebview(Context context, AttributeSet attrs) {
super(context, attrs);
setClickable(false);
setLongClickable(false);
setFocusable(false);
setFocusableInTouchMode(false);
}
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return false;
}
}
Setup to parent layout of each WebView:
android:descendantFocusability="blocksDescendants"
android:layout_width="match_parent"
android:layout_height="wrap_content"
I just tried what is suggested in this post WebView inside the Custom ListView: Click Listener is not Working, I dunno why but if you set these features in the XML they don't seem to work. Doing this dynamically does allow you to click on the listview item =)
I was using the following layout in ListView and it was working perfectly, ie its clicking, scrolling and so on.
TextView1
ImageView1 TextView2 ImageView2
TextView3
Then I have changed the layout with following, ie I have added with WebView control in left most corner in place of ImageView1
TextView1
WebView TextView2 ImageView2
TextView3
After doing this, clicking was not working for me.
I solve this problem by adding this to the Webview:
webView.setFocusable(false);
webView.setClickable(false);