110

So I have a fascinating problem. Despite the fact that I'm not manually or programmatically scrolling my view, my WebView is being automatically scrolled to after the data inside it loads.

I've got a fragment in a viewpager. When I first load the pager, it works as expected and everything is shown. But once I "flip the page" the data loads and the WebView pops up to the top of the page, hiding the views above it, which is undesirable.

Does anyone know how to prevent this from happening?

My layout looks like such:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/article_title"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="2dp"
            android:text="Some Title"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:textColor="@color/article_title"
            android:textStyle="bold" />

        <LinearLayout
            android:id="@+id/LL_Seperator"
            android:layout_width="fill_parent"
            android:layout_height="1dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:background="@color/text"
            android:orientation="horizontal" >
        </LinearLayout>

        <WebView
            android:id="@+id/article_content"
            android:layout_width="match_parent"
            android:layout_marginRight="10dp"
            android:layout_marginLeft="10dp"
            android:layout_height="wrap_content" />

        <TextView
            android:id="@+id/article_link"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="5dp"
            android:layout_marginRight="10dp"
            android:layout_marginLeft="10dp"
            android:text="View Full Article"
            android:textColor="@color/article_title"
            android:textStyle="bold" />
    </LinearLayout>

</ScrollView>

I'm also not giving focus to anything. By default, it seems to automatically scroll to the WebView after it has loaded. How do I prevent this?

Navarr
  • 3,703
  • 7
  • 33
  • 57

8 Answers8

269

I had the same problem, after hours of trying several ideas, what finally worked for me was simply adding the descendantFocusability attribute to the ScrollView's containing LinearLayout, with the value blocksDescendants. In your case:

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:descendantFocusability="blocksDescendants" >

Haven't had the problem reoccur since.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
mjp66
  • 4,214
  • 6
  • 26
  • 31
  • 3
    Does this have any negative impact on the accessibility of these controls? – Cory Trese Mar 22 '14 at 23:53
  • 37
    Note that if there are any child views like EditText, this method will cause them to become uneditable. – djhworld Mar 24 '14 at 23:10
  • 2
    This question/answer doesn't come up when you search for the words ScrollView Webview autoscroll, and it should. Maybe this comment will help! Had the same issue with using a WebViewFragment and didn't find this question even after lots of searching until I posted my own question (now deleted). – Colin M. May 29 '14 at 17:28
  • Good answer. It would be good if you can explain View priorities for taking focus in android – VVB Feb 17 '16 at 10:50
  • 1
    Working on a Xamarin.Android project, had auto scroll trouble in a scrollview with multiple gridviews, populated asynchronously with downloaded images. This solution worked so perfectly I had trouble to believe it at first sight and had to test it again. – YumeYume Aug 19 '16 at 08:26
  • 1
    The very same issue happens for Ads in a `RecyclerView` as well. Your solution works in that case as well :) – Minas Mina Feb 22 '17 at 17:08
  • I think it's because when onLayout() is called in any ScrollView, it checks to see if any child has focus. If they do, the ScrollView will automatically scroll to that child. When new things load inside the ScrollView, I believe it somehow takes the focus, and that's what causes the problem. – Justin Liu Feb 23 '17 at 09:23
  • I had a recycler view (A), inside a recycler view (B) and the page was jumping when the data was put into recycler view (B). I tried overriding the laymanager for recycler view (A) and disabling vertical scrolling and it was a solution, but I needed to enable it after the data was entered into recycler view (B) but I got it working. Messy fix. This fix has saved me so much hassle. Cheers – Killesk Jun 27 '17 at 14:05
44

You can simply add this to your LinearLayout: android:focusableInTouchMode="true". It works for me.

 <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusableInTouchMode="true"
    android:orientation="vertical" >
Peter Nguyen
  • 706
  • 7
  • 9
27

You should create new class extend ScrollView, then Override requestChildFocus:

public class MyScrollView extends ScrollView {

    @Override 
    public void requestChildFocus(View child, View focused) { 
        if (focused instanceof WebView ) 
           return;
        super.requestChildFocus(child, focused);
    }
}

Then in your xml layout, using:

<MyScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background" >

That works for me. The ScrollView will not auto scroll to the WebView anymore.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
user1417127
  • 1,525
  • 1
  • 21
  • 29
  • 5
    Also needed constructors: `public ExtendedScrollView(Context context) { super(context); } public ExtendedScrollView( Context context, AttributeSet attributeSet) { super(context, attributeSet); } public ExtendedScrollView( Context context, AttributeSet attributeSet, int defStyle) { super(context, attributeSet, defStyle); }` – Erik B Oct 29 '12 at 17:58
6

Adding these line in main layout solves the problem

android:descendantFocusability="blocksDescendants"
brasofilo
  • 25,496
  • 15
  • 91
  • 179
arun-r
  • 3,104
  • 2
  • 22
  • 20
4

Like this:

<com.ya.test.view.MyScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:descendantFocusability="beforeDescendants"
        android:focusable="true"
        android:focusableInTouchMode="true" >
YaC King
  • 109
  • 1
  • 8
4

Probably there are people who have the same problem I was having, so I'll help out.

I was trying to put android:descendantFocusability="beforeDescendants" in my main ScrollView as following:

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="beforeDescendants">
    /*my linearlayout or whatever to hold the views */

and it wasn't working, so I had to make a RelativeLayout the parent of the ScrollView, and place the android:descendantFocusability="beforeDescendants" in the parent aswell.

So I solved it doing the following:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants">

<ScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">
/*my linearlayout or whatever to hold the views */
James
  • 3,580
  • 3
  • 25
  • 36
0

I added: android:overScrollMode="never" in my ScrollView and set the height to wrap_content.

My view was very complex as it was legacy code with LinearLayout inside LinearLayout inside LinearLayout.

This helped me, hope it will help someone else too!

Ahmed Shahid
  • 300
  • 3
  • 9
-2

I had to use the fully qualified name for MyScrollView, otherwise I got an inflate exception.

<com.mypackagename.MyScrollView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/background" >
Cathal Coffey
  • 1,105
  • 2
  • 20
  • 35