Android: ScrollView заставляет дно


200

Я бы хотел, чтобы ScrollView начинался с самого низа. Любые методы?


1
Я думаю, что это просто scrollTo (), да, я только что проверил документы разработчика для ScrollView. Очень просто.
Ноа Сейдман

Ответы:


274

scroll.fullScroll(View.FOCUS_DOWN) Также должно работать.

Поместите это в scroll.Post(Runnable run)

Код Котлина

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}

6
Это, кажется, ничего не делает, какие-либо предложения? Я попробовал это на OnCreate, а затем в OnClick кнопки.
Ричард Джонн

Кажется, это не работает для изменения ориентации. В противном случае это работает.
Прашант

1
Это не работает, если размер макета изменился прямо перед вызовом. Это должно быть отправлено вместо этого.
MLProgrammer-CiM

2
Это и ниже не сработает, пока вы не дадите некоторое время представлению полностью наполниться, просто упрощая ответ ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Or Down);}}, 1000);
EngineSense

scroll.fullScroll (View.FOCUS_DOWN) приведет к изменению фокуса. Это приведет к некоторому странному поведению при наличии нескольких фокусируемых видов, например, двух EditText. Проверьте другое решение, которое я предоставляю внизу.
Peacepassion

332

Вы должны запустить код внутри scroll.post так:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});

4
есть какой-то способ без потери фокуса текущего элемента, когда я делаю это, я теряю фокус моего текущего элемента (отличается от scrollview)
rkmax

2
Это необходимо только в тех случаях, когда макет еще не был измерен и размещен (например, если вы запускаете его в onCreate). В таких случаях, как нажатие кнопки, .post () не требуется.
Патрик Боос

12
Если вы не хотите фокусироваться на ScrollView, вы можете использовать его scroll.scrollTo(0, scroll.getHeight());для перехода к нижней части scroll.smoothScrollTo(0, scroll.getHeight());
экрана

Разве этот код не является возможной утечкой памяти? Создается анонимный Runnable, который содержит ссылку на представление активности (прокрутки). Если действие будет уничтожено в то время, когда исполняемый файл выполняет свою задачу, он утечет ссылкой на представление прокрутки, нет?
Дженевер

В Котлине:scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) }
Альберт Вила Кальво

94

scroll.fullScroll(View.FOCUS_DOWN)приведет к смене фокуса. Это приведет к некоторому странному поведению при наличии нескольких фокусируемых видов, например, двух EditText. Есть другой способ для этого вопроса.

    View lastChild = scrollLayout.getChildAt(scrollLayout.getChildCount() - 1);
    int bottom = lastChild.getBottom() + scrollLayout.getPaddingBottom();
    int sy = scrollLayout.getScrollY();
    int sh = scrollLayout.getHeight();
    int delta = bottom - (sy + sh);

    scrollLayout.smoothScrollBy(0, delta);

Это хорошо работает.

Удлинение Котлина

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}

Так рада, что мне не пришлось больше тратить время на это. Как раз то, что мне было нужно
Александр Г

6
Это должно иметь больше голосов. Это лучший ответ на сегодняшний день.
Эрик Ланге,

1
Это лучший ответ, присутствующий здесь.
указатель недействителен

1
Перепробовал все остальное на этой странице, даже материал намного ниже этого. Это было единственное, что сработало, и это не заставляет мой EditText терять фокус. Спасибо.
Джоэл

Если вам нужно прокрутить вниз, когда клавиатура появляется, объедините этот код с этой библиотекой . Работает как шарм.
wonsuc

47

Иногда scrollView.post не работает

 scrollView.post(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    });

НО если вы используете scrollView.postDelayed, он точно будет работать

 scrollView.postDelayed(new Runnable() {
        @Override
        public void run() {
            scrollView.fullScroll(ScrollView.FOCUS_DOWN);
        }
    },1000);

спасибо за идентификацию. postDelayed - лучшее решение.
Прашант

@Prashant :) :) :)
Ajay Shrestha

1
Просто помните, что вам нужно избавиться от своего Runnable, когда вы закончите упражнение
FabioR

38

Что лучше всего сработало для меня

scroll_view.post(new Runnable() {
     @Override
     public void run() {
         // This method works but animates the scrolling 
         // which looks weird on first load
         // scroll_view.fullScroll(View.FOCUS_DOWN);

         // This method works even better because there are no animations.
         scroll_view.scrollTo(0, scroll_view.getBottom());
     }
});

Я пробовал это, но алгоритм здесь неверен. Проверьте мой ответ внизу, пожалуйста.
Peacepassion

28

Я увеличиваю, чтобы работать отлично.

    private void sendScroll(){
        final Handler handler = new Handler();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {Thread.sleep(100);} catch (InterruptedException e) {}
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        scrollView.fullScroll(View.FOCUS_DOWN);
                    }
                });
            }
        }).start();
    }

Заметка

Этот ответ - обходной путь для действительно старых версий Android. Сегодня postDelayedэта ошибка больше не существует, и вы должны ее использовать.


3
Не выше двух, но это хорошо работает в моем телефоне (LG JellyBean 4.1.2 Optimus G).
Youngjae

9
Почему бы не использовать scrollView.postDelayed (runnable, 100)?
Мэтт Вулф

1
@MattWolfe в то время не работал в некоторых старых версиях Android. Но сегодня этот ответ вообще не рекомендуется.
ademar111190

4
Ради любви к Богу, используйте scrollView.postDelayed (runnable, 100)! :)
Алекс Локвуд

1
Я добавил примечание @AlexLockwood, я надеюсь, что люди используют postDelayed:)
ademar111190

4

Я попробовал это успешно.

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);

3

Когда представление еще не загружено, вы не можете прокрутить. Вы можете сделать это «позже» с помощью поста или вызова в спящем режиме, как указано выше, но это не очень элегантно.

Лучше спланировать прокрутку и сделать это на следующем onLayout (). Пример кода здесь:

https://stackoverflow.com/a/10209457/1310343


3

Одна вещь, чтобы рассмотреть то, что НЕ установить. Убедитесь, что ваши дочерние элементы управления, особенно элементы управления EditText, не имеют свойства RequestFocus. Это может быть одним из последних интерпретируемых свойств макета, и он будет переопределять параметры гравитации для своих родителей (макет или ScrollView).


3

Вот еще несколько способов прокрутки вниз

fun ScrollView.scrollToBottom() {
    // use this for scroll immediately
    scrollTo(0, this.getChildAt(0).height) 

    // or this for smooth scroll
    //smoothScrollBy(0, this.getChildAt(0).height)

    // or this for **very** smooth scroll
    //ObjectAnimator.ofInt(this, "scrollY", this.getChildAt(0).height).setDuration(2000).start()
}

С помощью

Если вы уже выложили скроллвью

my_scroll_view.scrollToBottom()

Если ваше прокручиваемое представление не закончено (например: вы прокрутите вниз в onCreateметоде Activity ...)

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}

1

Не совсем ответ на вопрос, но мне нужно было прокрутить вниз, как только EditText получил фокус. Однако принятый ответ заставил бы ET также сразу потерять фокус (к ScrollView, который я предполагаю).

Мой обходной путь был следующим:

emailEt.setOnFocusChangeListener(new View.OnFocusChangeListener() {
    @Override
    public void onFocusChange(View v, boolean hasFocus) {
        if(hasFocus){
            Toast.makeText(getActivity(), "got the focus", Toast.LENGTH_LONG).show();
            scrollView.postDelayed(new Runnable() {
                @Override
                public void run() {
                    scrollView.fullScroll(ScrollView.FOCUS_DOWN);
                }
            }, 200);
        }else {
            Toast.makeText(getActivity(), "lost the focus", Toast.LENGTH_LONG).show();
        }
    }
});

1

Я на самом деле обнаружил, что двойной вызов fullScroll делает свое дело:

myScrollView.fullScroll(View.FOCUS_DOWN);

myScrollView.post(new Runnable() {
    @Override
    public void run() {
        myScrollView.fullScroll(View.FOCUS_DOWN);
    }
});

Это может быть связано с активацией метода post () сразу после выполнения первой (неудачной) прокрутки. Я думаю, что такое поведение происходит после любого предыдущего вызова метода в myScrollView, поэтому вы можете попробовать заменить первый метод fullScroll () на что-либо еще, что может иметь отношение к вам.


0

Использование есть еще один крутой способ сделать это с сопрограммами Kotlin. Преимущество использования сопрограммы по сравнению с обработчиком с работоспособным (post / postDelayed) состоит в том, что он не запускает дорогой поток для выполнения отложенного действия.

launch(UI){
    delay(300)
    scrollView.fullScroll(View.FOCUS_DOWN)
}

Важно указать HandlerContext сопрограммы в качестве пользовательского интерфейса, в противном случае отложенное действие не может быть вызвано из потока пользовательского интерфейса.


0

В этих случаях использовалось только scroll.scrollTo (0, sc.getBottom ()) не работают, используйте его с помощью scroll.post

Пример:

scroll.post(new Runnable() {
  @Override
  public void run() {
  scroll.fullScroll(View.FOCUS_DOWN);
  } 
});

0

Одна возможная причина того, почему scroll.fullScroll(View.FOCUS_DOWN)не может работать, даже завернутый в.post() заключается в том, что представление не выложено. В этом случае View.doOnLayout () может быть лучшим вариантом:

scroll.doOnLayout(){
    scroll.fullScroll(View.FOCUS_DOWN)
}

Или что-то более проработанное для смелых душ: https://chris.banes.dev/2019/12/03/suspending-views/

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.