Android: усилие прокрутки вниз

Я бы хотел, чтобы ScrollView начинался полностью снизу. Какие-нибудь методы?


person Noah Seidman    schedule 20.06.2010    source источник
comment
Я думаю, это просто scrollTo (), да, я только что проверил документацию разработчика для ScrollView. Очень просто.   -  person Noah Seidman    schedule 20.06.2010


Ответы (18)


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

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

Код Котлина

scrollView.post {
   scrollView.fullScroll(View.FOCUS_DOWN)
}
person CommonsWare    schedule 20.06.2010
comment
Кажется, это ничего не дает, какие-либо предложения? Я попробовал это на onCreate, а затем на onClick кнопки. - person RichardJohnn; 02.08.2010
comment
Похоже, это не помогает изменить ориентацию. В противном случае его работа. - person Prashant; 19.03.2015
comment
Это не сработает, если размер макета изменился прямо перед его вызовом. Вместо этого его нужно опубликовать. - person MLProgrammer-CiM; 09.04.2015
comment
Это и ниже не будут работать, пока вы не дадите некоторое время на то, чтобы представление полностью раздулось, просто упрощая ответ ademar. scrollView.postDelayed (new Runnable () {@Override public void run () {scrollView.fullScroll (View.FOCUS_UP // Or Down);}}, 1000); - person EngineSense; 31.12.2015
comment
scroll.fullScroll (View.FOCUS_DOWN) приведет к изменению фокуса. Это приведет к некоторому странному поведению, когда есть более одного фокусируемого представления, например, два EditText. Отметьте другое решение, которое я предлагаю внизу. - person peacepassion; 19.01.2016
comment
scroll.fullScroll(View.FOCUS_DOWN) приведет к изменению фокуса. Это приведет к некоторому странному поведению, когда есть более одного фокусируемого представления, например, два EditText. Проверьте мой ответ ниже. - person peacepassion; 02.09.2017
comment
См. Ответ ниже - person Ajay Shrestha; 24.03.2018
comment
В этом случае scroll.scrollTo (0, sc.getBottom ()) не работает, используйте scroll.post. Пример: scroll.post (new Runnable () {@Override public void run () {scroll.fullScroll (View.FOCUS_DOWN);}}); - person nnyerges; 27.02.2019
comment
@eCDroid: Этого не было в моем первоначальном ответе; он был добавлен в редакцию. Основываясь на некоторых других ответах на этот вопрос, я предполагаю, что проблема заключается в том, выкладывается ли ScrollView во время вызова fullScroll(). Если это так, то более эффективным подходом, если вы используете Kotlin, будет использование _ 3_ из Android KTX. - person CommonsWare; 05.05.2020
comment
@EngineSense Это была именно моя проблема, я думал, что ничего не работает, но макету просто потребовалось несколько миллисекунд, чтобы приспособиться к новому размеру! (Я использовал 500 мс кстати) - person Big_Chair; 29.08.2020
comment
binding.scroll.run { post { fullScroll(View.FOCUS_DOWN) } } легко;) - person murt; 23.04.2021

вы должны запустить код внутри scroll.post следующим образом:

scroll.post(new Runnable() {            
    @Override
    public void run() {
           scroll.fullScroll(View.FOCUS_DOWN);              
    }
});
person hungson175    schedule 24.12.2010
comment
есть способ не потерять фокус текущего элемента, когда я делаю это, я теряю фокус моего текущего элемента (отличается от scrollview) - person rkmax; 21.09.2014
comment
Это необходимо только в тех случаях, когда макет еще не был измерен и размечен (например, если вы запускаете его в onCreate). В таких случаях, как нажатие кнопки, .post () не нужен. - person Patrick Boos; 12.01.2015
comment
Если вы не хотите сосредотачиваться на ScrollView, вы можете использовать scroll.scrollTo(0, scroll.getHeight()); для перехода вниз или scroll.smoothScrollTo(0, scroll.getHeight()); для более плавной прокрутки. - person yuval; 27.04.2016
comment
Не является ли этот код возможной утечкой памяти? Создается анонимный Runnable, который содержит ссылку на представление активности (прокрутки). Если действие будет уничтожено, пока runnable выполняет свою задачу, произойдет утечка ссылки на scrollview, не так ли? - person Jenever; 19.01.2018
comment
В Котлине: scrollView.post { scrollView.fullScroll(View.FOCUS_DOWN) } - person Albert Vila Calvo; 27.05.2019
comment
@AlbertVilaCalvo, код в вашем комментарии у меня сработал и довел мой свиток до самого конца. Большинство решений здесь останавливали прокрутку немного до конца для меня. Спасибо !! - person Nafeez Quraishi; 17.11.2020

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);

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

Расширение Kotlin

fun ScrollView.scrollToBottom() {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)        
    smoothScrollBy(0, delta)
}
person peacepassion    schedule 19.01.2016
comment
Так рада, что мне не пришлось больше тратить на это время. То, что мне было нужно - person Alexandre G; 16.05.2016
comment
У этого должно быть больше голосов. На сегодняшний день это лучший ответ. - person Eric Lange; 09.10.2016
comment
Это лучший ответ, представленный здесь. - person void pointer; 12.10.2016
comment
Пробовал все остальное на этой странице, даже то, что ниже. Это было единственное, что сработало, и это не привело к потере фокуса моего EditText. Спасибо. - person Joel; 05.01.2017
comment
Если вам нужно прокрутить вниз, пока отображается клавиатура, объедините этот код с этой библиотекой. Работает как шарм. - person wonsuc; 19.01.2018
comment
менее хакерское решение без всяких сомнений - person desgraci; 20.06.2019
comment
Это следует считать правильным ответом, отлично работает - person FabioR; 22.08.2019
comment
ScrollView имеет только один дочерний элемент, который является ViewGroup, поэтому вы можете просто сказать val lastChild = getChildAt(0) - person Ian Elvister; 12.03.2021
comment
Я не знаю почему, но для меня я не прокручиваю вниз! - person Kishan Solanki; 05.06.2021
comment
Это лучший ответ. Не выглядит хакерским и плавно прокручивается. Если вам нужно это поведение в вашем методе on create, обязательно оберните его в блок postDelayed или дождитесь, пока макет представления будет полностью выложен - person Alfred Afutu; 28.06.2021

Иногда 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);
person Ajay Shrestha    schedule 26.07.2016
comment
спасибо за идентификацию. postDelayed - лучшее решение. - person Prashant; 23.03.2018
comment
@Prashant :) :) :) - person Ajay Shrestha; 24.03.2018
comment
Просто помните, что вам нужно избавиться от Runnable, когда вы закончите действие. - person FabioR; 22.08.2019

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

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());
     }
});
person https    schedule 27.02.2014
comment
Я пробовал это, но алгоритм здесь неправильный. Пожалуйста, проверьте мой ответ внизу. - person peacepassion; 19.01.2016

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

    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 больше не содержит этой ошибки, и вам следует ее использовать.

person ademar111190    schedule 06.01.2012
comment
Не выше двух, но это хорошо работает в моем телефоне (LG JellyBean 4.1.2 Optimus G). - person Youngjae; 29.05.2013
comment
Почему бы не использовать scrollView.postDelayed (runnable, 100)? - person Matt Wolfe; 14.08.2014
comment
@MattWolfe в то время не работал в некоторых старых версиях android. Но сегодня этот ответ вообще не рекомендуется. - person ademar111190; 14.08.2014
comment
Ради бога используйте scrollView.postDelayed (runnable, 100)! :) - person Alex Lockwood; 05.01.2016
comment
Добавил заметку @AlexLockwood, надеюсь народ использует postDelayed :) - person ademar111190; 05.01.2016

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

scrollView.postDelayed(new Runnable() {
    @Override
    public void run() {
        scrollView.smoothScrollTo(0, scrollView.getHeight());
    }
}, 1000);
person Yusuf Yaşar    schedule 18.04.2020

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

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

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

person Frank    schedule 10.05.2012

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

person Epsilon3    schedule 10.09.2013

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

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()
}

Использование

Если вы scrollview уже выложили

my_scroll_view.scrollToBottom()

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

my_scroll_view.post { 
   my_scroll_view.scrollToBottom()          
}
person Linh    schedule 03.04.2019

Не совсем ответ на вопрос, но мне нужно было прокрутить вниз, как только 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();
        }
    }
});
person Teo Inke    schedule 20.06.2016

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

myScrollView.fullScroll(View.FOCUS_DOWN);

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

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

person BarLr    schedule 08.01.2019

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

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

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

person Phaestion    schedule 09.04.2018

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

Пример:

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

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

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

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

person Ghedeon    schedule 14.04.2020

Это работает мгновенно. Без задержки.

// wait for the scroll view to be laid out
scrollView.post(new Runnable() {
  public void run() {
    // then wait for the child of the scroll view (normally a LinearLayout) to be laid out
    scrollView.getChildAt(0).post(new Runnable() {
      public void run() {
        // finally scroll without animation
        scrollView.scrollTo(0, scrollView.getBottom());
      }
    }
  }
}
person Audi Nugraha    schedule 09.07.2020

Если ваш минимальный SDK составляет 23 или выше, вы можете использовать это:

View childView = findViewById(R.id.your_view_id_in_the_scroll_view)
if(childView != null){
  scrollview.post(() -> scrollview.scrollToDescendant(childView));
}
person MeLine    schedule 15.02.2021

Сочетание всех ответов помогло мне:

Функция расширения PostDelayed

private fun ScrollView.postDelayed(
    time: Long = 325, // ms
    block: ScrollView.() -> Unit
) {
    postDelayed({block()}, time)
}

Расширение Функция measureScrollHeight

fun ScrollView.measureScrollHeight(): Int {
    val lastChild = getChildAt(childCount - 1)
    val bottom = lastChild.bottom + paddingBottom
    val delta = bottom - (scrollY+ height)
    return delta
}

Функция расширения ScrolltoBottom

fun ScrollView.scrollToBottom() {
    postDelayed {
        smoothScrollBy(0, measureScrollHeight())
    }
}

Имейте в виду, что минимальная задержка должна быть не менее 325 мс, иначе прокрутка будет ошибочной (не до конца). Чем больше ваша дельта между текущей высотой и дном, тем больше должно быть время задержки.

person Andrew    schedule 22.06.2021