Как прокрутить к началу длинного макета ScrollView?

162

Для части моего приложения пользователю предоставляется список имен, и ему предлагается сгруппировать их по своему усмотрению.

(Обратите внимание, что код ListView дословно скопирован из учебника по Android Views. Я еще не настроил его под свои нужды, я просто пытаюсь выяснить, как заставить это работать.)

Базовый макет представляет собой LinearLayout, содержащий ScrollView (называемый «groupsScrollView» в приведенном ниже коде), содержащий RelativeLayout. У меня есть несколько кнопок и текста, а затем мой ListView, который отображает список имен. Все это выше видимой области экрана, поэтому пользователю предоставляется возможность прокрутки по вертикали, чтобы увидеть все это.

Все это прекрасно работает, за исключением того, что когда страница загружается, она всегда предварительно прокручивается в верхнюю часть моего ListView - в середине страницы. Текст и кнопки, которые я создал, сообщают пользователю, что делать, не видны.

Я могу схватить экран и прокрутить вверх, это прекрасно работает, но я бы хотел, чтобы экран загружался уже после прокрутки вверх. Пользователю не нужно прокручивать UP, чтобы увидеть верхнюю часть недавно загруженной страницы. Но все, что я пытался программно прокрутить до верхней части экрана, не удалось.

Вот мой метод onCreate:

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.groups);

    mainScrollView = (ScrollView)findViewById(R.id.groupsScrollView);

    //get the Bundle out of the Intent...
    Bundle extras = getIntent().getExtras();
    mNames = extras.getStringArray("mNames");

    setListAdapter(new ArrayAdapter<String>(this, R.layout.list_item, mNames));

    ListView lv = getListView();
    lv.setTextFilterEnabled(true);

    //This is the line I'm having issues with
    mainScrollView.pageScroll(View.FOCUS_UP);

    lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view,
            int position, long id) {
          // When clicked, show a toast with the TextView text
          Toast.makeText(getApplicationContext(), ((TextView) view).getText(),
              Toast.LENGTH_SHORT).show();
        }
      });
}

Строка "mainScrollView.pageScroll (View.FOCUS_UP); это проблема. Она не вызывает ошибку, но, похоже, ничего не делает. Я пробовал scrollTo (0,0), scrollDirection (View.FOCUS_UP). ) и все остальное, что я могу придумать.

Поскольку я не получаю сообщение об ошибке, я должен предположить, что эти команды прокрутки действительно работают, но они прокручиваются до верхней части ListView, а не до верхней части ScrollView или RelativeLayout, который его содержит. Это подтверждается собственным описанием Google метода scrollTo (int x, int y), в котором говорится: «Эта версия также ограничивает прокрутку до границ нашего ребенка».

Итак, чтобы сделать длинный вопрос еще длиннее, как я могу загрузить несколько представлений на экране, содержащихся в ScrollView, а затем программно прокрутить все это вверх страницы, чтобы пользователь мог взаимодействовать с ним?

Спасибо!

Гленн
источник

Ответы:

264

Пытаться

mainScrollView.fullScroll(ScrollView.FOCUS_UP);

он должен работать.

roomtek
источник
У меня тоже работает : D
Мунтасир Аоник
1
Я обнаружил, что ScrollView # fullScroll () меняет текущий фокус. Я тестировал с EditText.
illusionJJ
175

Была такая же проблема, вероятно, какая-то ошибка.

Даже fullScroll(ScrollView.FOCUS_UP)другой ответ не сработал.
Единственная вещь, которая работала для меня, звонила scroll_view.smoothScrollTo(0,0)сразу после показа диалога.

Мохамед Хафез
источник
Сначала это работало, но позже, когда я попытался сделать это снова и снова, этот подход не дал удовлетворительного результата.
JaydeepW
16
я решаю из scroll_view.smoothScrollTo (0,0), когда у нас есть просмотр списка в стороне, просмотр прокрутки в то время fullScroll (ScrollView.FOCUS_UP) не будет работать.
Киртикумар А.
1
scroll_view.smoothScrollTo (0,0) работал для меня лучше, чем mainScrollView.fullScroll (ScrollView.FOCUS_UP); СПАСИБО!
Мариенке
2
На большинстве устройств fullScroll (ScrollView.FOCUS_UP) работал, но на Nexus 5 и устройствах, где у меня был увеличен размер текста - fullSscroll, перемещенный под панелью действий, smoothScrollTo (0,0) работал лучше на всех устройствах.
JT-Gilkeson
Это также имеет преимущество перед fullScroll()тем, что выбранный элемент остается выбранным после перемещения. С fullScroll()помощью первый элемент в просмотре прокрутки каждый раз перевыбирался в моем случае независимо от выбранного элемента до того, как прокрутка переместилась вверх.
GeertVc
97

У меня была такая же проблема, и это решило ее. Надеюсь, это поможет вам.

listView.setFocusable(false);
Мигель Паласиос
источник
3
Это правильное решение и для gridviews. Это происходит, когда у вас есть несколько элементов представления в одной и той же группе представлений, особенно другое представление списка сверху списка или представление сетки. Поскольку адаптер уведомляет поток пользовательского интерфейса, представление воссоздается и прокручивается до первого элемента. Просто вызовите listView.setFocusable (false) / gridView.setFocusable (false). Если вы делаете это из XML-файла, он не будет работать, хотя.
Омерсем
Это решение работало и в моем случае, у меня был RecyclerView внутри NestedScrollView, поэтому он автоматически прокручивался вниз. Спасибо чувак!
Nilesh Rathore
Я должен был добавить это до установки адаптера, но после этого работает как шарм. Спасибо
Сообщество
идеальное объяснение !!
Борха Лопес
Спасибо и Мигелю, и особенно Омерсему за объяснение, особенно ту часть о том, как это не будет работать, если установлено в XML, это избавило меня от головной боли
buradd
53

scrollViewObject.fullScroll(ScrollView.FOCUS_UP)это работает нормально, но проблема заключается только в том, что при заполнении данных в scrollViewObject вызывается немедленно. Вам нужно подождать несколько миллисекунд, пока данные не будут заполнены. Попробуйте этот код:

scrollViewObject.postDelayed(new Runnable() {
    @Override
    public void run() {
        scroll.fullScroll(ScrollView.FOCUS_UP);
    }
}, 600);

ИЛИ

 scrollViewObject.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        scrollViewObject.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        scrollViewObject.fullScroll(View.FOCUS_UP);
    }
});
Мохаммед Имран
источник
Я имел дело с той же проблемой, когда прокрутка должна была прокручиваться вниз страницы, исправлена!
Machine Tribe
1
Вместо того, чтобы угадывать «магическое» x число миллисекунд, которое вам нужно ждать, объекты View предлагают метод post (Runnable), который вы можете использовать, который будет публиковать runnable, когда виджет будет отображаться в пользовательском интерфейсе.
Райан
@Ryan: пост (Runnable) всегда не работает для меня на Nexus 5 (Genymotion)
Dika
post (Runnable) может не работать, потому что если вы извлекаете данные после шага обновления, то сначала работает прокрутка вверх, а затем данные заполняются до представления. Поэтому вам следует либо использовать postDelayed (Runnable, dummyMillis), либо использовать scroll.fullScroll (ScrollView.FOCUS_UP) после заполнения данных процессами.
огужан
Ваше первое решение, в котором вы даете статический миллис, - плохой подход.
Малвиндер Сингх
35

Основная проблема всех этих правильных решений заключается в том, что вы пытаетесь переместить прокрутку вверх, когда она еще не нарисована на экране.

Вам нужно подождать, пока на экране не появится вид прокрутки, а затем переместить его в любое из этих решений. Это лучшее решение, чем пост-задержка, потому что вы не против задержки.

    // Wait until my scrollView is ready
    scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            // Ready, move up
            scrollView.fullScroll(View.FOCUS_UP);
        }
    });
Pelanes
источник
7
Хорошее решение - не забудьте удалить Global Listener в конце onGlobalLayoutвызова метода scrollView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
Nilhcem
30

Очень просто

    ScrollView scroll = (ScrollView) findViewById(R.id.addresses_scroll);
    scroll.setFocusableInTouchMode(true);
    scroll.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
CommonSenseCode
источник
3
для меня это не сработало (3-я строка), решение было: scroll.fullScroll (View.FOCUS_UP); (включая ваши первые 2 строки)
medskill
@ medskill, Привет, ты написал это в своем XML-файле? Я считаю, что это работает только в onCreate().
неизвестно
@ imknownJ.Kimu Работает для меня в XML-файле
Paglian
Это сработало для меня. Вам нужна как вторая, так и третья строка. Это не будет работать в XML для меня.
ET
2
Я бы поцеловал тебя, если бы мог! Потратил на это 1-2 часа. Лучшее, когда ожидают загрузки двух списков и не хотят фокусироваться на них. Добавил его в onResume ().
Джон Т
24

Я столкнулся с той же проблемой, когда я использую Scrollview внутри View Flipper или Dialog, этот случай scrollViewObject.fullScroll(ScrollView.FOCUS_UP)возвращает false, так что случай scrollViewObject.smoothScrollTo(0, 0)работает для меня

Верхняя часть с прокруткой

sravan
источник
19
 final ScrollView scrollview = (ScrollView)findViewById(R.id.selected_place_layout_scrollview);

         scrollview.post(new Runnable() { 
                public void run() { 
                    scrollview.scrollTo(0, 0); 
                } 
            }); 
Младен Раконяк
источник
9
runOnUiThread( new Runnable(){
   @Override
   public void run(){
      mainScrollView.fullScroll(ScrollView.FOCUS_UP);
   }
}
traeper
источник
9

Это работает для меня

scroll_view.smoothScrollTo(0,0); // scroll to top of screen
Панкадж Талавия
источник
6

Это принудительная прокрутка для scrollview :

            scrollView.post(new Runnable() {
                @Override
                public void run() {
                    scrollView.scrollTo(0, 0);
                    scrollView.pageScroll(View.FOCUS_UP);
                    scrollView.smoothScrollTo(0,0);
                }
            });
Хади Примечание
источник
4
scrollView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        // Ready, move up
        scrollView.fullScroll(View.FOCUS_UP);
    }
});

источник
1

Я исправил свою проблему в Kotlin следующим образом:

scrollview.isFocusableInTouchMode = true
scrollview.fullScroll(View.FOCUS_UP)
scrollview.smoothScrollTo(0,0)
МаК
источник
0
@SuppressWarnings({ "deprecation", "unchecked" })
public void swipeTopToBottom(AppiumDriver<MobileElement> driver) 
                    throws InterruptedException {
       Dimension dimensions = driver.manage().window().getSize();
        Double screenHeightStart = dimensions.getHeight() * 0.30;
        int scrollStart = screenHeightStart.intValue();
        System.out.println("s="+scrollStart);
        Double screenHeightEnd = dimensions.getHeight()*0.90;
        int scrollEnd = screenHeightEnd.intValue();
        driver.swipe(0,scrollStart,0,scrollEnd,2000);
        CommonUtils.threadWait(driver, 3000);
    }
Аджит Гур
источник
это будет работать наверняка,
Ajeet
Пожалуйста, дайте краткое объяснение того, как этот ответ решает проблему.
Айберк Озгюр