Android ScrollView doesn't start at top, but a

2019-01-31 03:15发布

问题:

I have a problem with a ScrollView that has inside of it a personalized GridView and other tipe of views.The first time I start the Activity, the ScrollView starts at its top, but if I visit the Activity other times the ScrollView starts at the beginning of the GridView.I used the class ExpandableHeightGridView found in this link for my GridView. The xml code for the Activity layout is this one:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollViewLuogo"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff" >

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#fff" >

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >

        <ImageView
            android:id="@+id/imageView1"
            android:layout_width="150dp"
            android:layout_height="100dp"
            android:layout_marginLeft="14dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:adjustViewBounds="true"
            android:maxHeight="200dp"
            android:maxWidth="200dp"
            android:scaleType="fitXY"
            android:src="@android:drawable/ic_menu_gallery" />

        <LinearLayout
            android:id="@+id/linearLayout1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="10dp"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/nomeTVActivityLuogo"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textStyle="bold"
                android:textSize="17sp"
                android:textColor="#005788" />

            <TextView
                android:id="@+id/indirizzoTVActivityLuogo"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/linearLayout2"
        android:layout_marginTop="10dp"
        android:orientation="vertical" >

        <ImageView
            android:id="@+id/imageViewMappaLuogo"
            android:layout_width="wrap_content"
            android:layout_height="60dp"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="14dp"
            android:layout_marginRight="14dp"
            android:layout_marginTop="5dp"
            android:scaleType="fitXY"
            android:src="@drawable/sfondo_mappa" />

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="14dp"
            android:text="Immagini"
            android:textColor="#97d6f9" />

        <View
            android:layout_width="fill_parent"
            android:layout_height="2dp"
            android:layout_marginLeft="14dp"
            android:layout_marginRight="14dp"
            android:layout_marginTop="5dp"
            android:background="#97d6f9" />

        <com.example.mappine.ExpandableHeightGridView
            android:id="@+id/gridViewLuogo"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginBottom="10dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="10dp"
            android:numColumns="3" >
        </com.example.mappine.ExpandableHeightGridView>

    </LinearLayout>

</RelativeLayout>

I've tried using the code scrollView.fullScroll(ScrollView.FOCUS_UP); but it didn't work.And even with scrollView.scrollTo(0, 0); I didn't have success. The only code that worked was:

    scrollView.post(new Runnable() 
      { 
         public void run() { 
             scrollViewLuogo.fullScroll(ScrollView.FOCUS_UP); 
         } 
      });

but it makes a fast animation from the top of the GridView to the top of the screen and i don't like it.

Any suggestion??

回答1:

Solution:

Ok sorry if it is a late reply but I stumbled upon the same issue (only that I was using ListView instead) and with a bit of trial and error I found the solution to this:

Basically the problem lies in the fact that the GridView/ListView child automatically requests parent focus (ScrollView) when you "hack" and resize its content with ExpandableHeightGridView, which happens after layout is rendered, and hence you see that animation when trying to scroll it up with scrollTo() (happens AFTER layout is created and AFTER gridView is resized so any generic callback is useless to handle this programatically).

So then, the simplest solution I found was to simply disable focusable property on the ListView/GridView with:

listView.setFocusable(false);

That way when you first enter the activity, focus will default and not rely on Listview/GridView.

And all working fine =)



回答2:

The easiest way is to add on the parent ScrollView the following xml attributes:

android:descendantFocusability="beforeDescendants"
android:focusableInTouchMode="true"

That means that the ScrollView as a whole will be the one getting focus instead of any inner container when you launch the activity. This is also useful, for example, when you have an edit text inside your layout and you don't want it to get focus immediately and popup the keyboard when entering a screen (It's the same principle).

So, your ScrollView on top of your layout would look like this:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/scrollViewLuogo"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:descendantFocusability="beforeDescendants"
    android:focusableInTouchMode="true"
    android:background="#fff" >


回答3:

ScrollView

android:fitsSystemWindows="false"


回答4:

Simply add this line of code in the Child of ScrollView

android:focusableInTouchMode="true"


回答5:

If you want to scroll it to top/bottom programmatically, you can do this(it's from here):

For Focus to Down:

((ScrollView) findViewById(R.id.scrollView)).post(new Runnable() { 
    public void run() { 
        ((ScrollView) findViewById(R.id.scrollView)).fullScroll(View.FOCUS_DOWN); 
    } 
});

For Focus to Top

((ScrollView) findViewById(R.id.scrollView)).post(new Runnable() { 
    public void run() { 
        ((ScrollView) findViewById(R.id.scrollView)).fullScroll(View.FOCUS_UP); 
    } 
});


回答6:

Sadly the example you followed is extremely poor. ListViews and GridViews should never be placed into ScrollViews.

ScrollView's purpose is to give infinite height to its child view. List/GridView's purpose is to take a potentially very large data set and only generate enough item views to fill the space made available to it at a time for efficiency. Both are capable of scrolling their content without the other.

Putting a List/GridView in a ScrollView is saying, "unstoppable force, meet immovable object." Either you've defeated the point of List/GridView or you've defeated the point of ScrollView by combining them.

Better ways to include other content within the same scrolling region include using header/footer views with a ListView, or otherwise concatenating the contents of list adapters together into a single adapter. Creating ListView items that contain several items per row to form a grid for part of an adapter's content is straightforward.



回答7:

Simply add this two line in your parent layout

android:focusable ="true" android:focusableInTouchMode ="true"

Try this, Hope it will work for you



回答8:

I found a way to give the GridView a fixed size inside ScrollView, and enable scrolling it. That allows you to see the entire ScrollView without having to scroll all elements of the GridView, and it makes more sense to me that using an ExpandableHeightGridView.

To do so, you would have to implement a new class extending GridView and override onTouchEvent() to call requestDisallowInterceptTouchEvent(true). Thus, the parent view will leave the Grid intercept touch events.

GridViewScrollable.java:

package com.example;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.GridView;

public class GridViewScrollable extends GridView {

    public GridViewAdjuntos(Context context) {
        super(context);
    }

    public GridViewAdjuntos(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public GridViewAdjuntos(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev){
        // Called when a child does not want this parent and its ancestors to intercept touch events.
        requestDisallowInterceptTouchEvent(true);
        return super.onTouchEvent(ev);
    }
}

Add it in your layout with the characteristics and margins you want, inside a ScrollView:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:isScrollContainer="true" >

    <com.example.GridViewScrollable
    android:id="@+id/myGVS"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:numColumns="auto_fit"
    android:stretchMode="columnWidth" />

</ScrollView>

And just get it in your activity:

GridViewScrollable myGridView = (GridViewScrollable) findViewById(R.id.myGVS);

I hope it helps =)



回答9:

As a follow-up I'll share my pain as well. In my app I have a RecyclerView inside a NestedScrollView inside a CoordinatorLayout:

<CoordinatorLayout>
  <NestedScrollView id="@+id/content">

     .......

     <TextView android:id="@+id/header"/>

     <RecyclerView android:id="@+id/recyclerView"/>       

  </NestedScrollView>
</CoordinatorLayout>

Of course upon opening the activity, the page scrolled to include the recyclerView in the middle. None of the answers above worked, so I came up with the following solution:

@Override
protected void onCreate( Bundle savedInstanceState ) {
  ....
  content.setOnScrollChangeListener( new NestedScrollView.OnScrollChangeListener() {
    @Override
    public void onScrollChange( NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY ) {
      Rect scrollBounds = new Rect();
      v.getHitRect( scrollBounds );
      if( header.getLocalVisibleRect( scrollBounds ) ){
        if( View.VISIBLE != recyclerView.getVisibility() ){
          recyclerView.setVisibility( View.VISIBLE );
          fillRecyclerViewSomehow();
        }
      }
    }
  }
}

@Override
protected void onResume() {
  ...
  recyclerView.setVisibility( View.GONE ); // this effectively suppresses the focusability
}

HTH



回答10:

Simple way to achieve this is to set up an ID to your ScrollView in XML ... let's say

scrollView_main

After that you just need to go to your java file and declare it like a normal variable above the procedure onCreate to be a global one like this

ScrollView scrollView_main;

ok, now is time to go to onCreate procedure and declare this, to get connection with your ID from XML file

scrollView_main = (ScrollView)findViewById(R.id.scrollView_main);

and finally the code that will do the trick for your ScrollView to be scrolled on top, this is your answer

scrollView_main.smoothScrollTo(0,0); //set it on top