Ответ 1
В то время, когда вы выполняете свой fullScroll(), макет еще не выполнен, поэтому ScrollView использует "старый" размер для таблицы. Вместо прямого вызова функции fullScroll() используйте View.post(Runnable).
Я хочу иметь динамическую таблицу со строками, добавленными со временем в результате взаимодействия с пользователем, используя TableLayout внутри ScrollView. Это отлично работает, но когда я хочу прокрутить до конца таблицы, используя fullScroll()
, он всегда оставляет в стороне последнюю строку; то есть, она прокручивается так, чтобы вид был показан до последнего. Последняя строка видна при прокрутке вручную, а также в полосе прокрутки.
Я, конечно, открыт для предложений о том, как сделать из этого лучший вариант; но мне особенно интересно понять, почему fullScroll()
ведет себя так. Должен ли я дать ему другой параметр или вообще использовать что-то другое? Или он делает это, потому что недавно добавленная линия пока не видна? (если да, то как я могу это решить?) Или я пропустил еще одну очевидную вещь?
Следующий код реплицирует проблему:
TestActivity.java:
package com.example.android.tests;
import java.util.Random;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;
public class TestActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button) findViewById(R.id.AddRow)).setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Random rnd = new Random();
TableRow nr = new TableRow(v.getContext());
for (int c=0; c<3; c++) {
TextView nv = new TextView(v.getContext());
nv.setText(Integer.toString(rnd.nextInt(20)-10));
nr.addView(nv);
}
((TableLayout) findViewById(R.id.Table)).addView(nr);
// Scrolls to line before last - why?
((ScrollView) findViewById(R.id.TableScroller)).fullScroll(View.FOCUS_DOWN);
}
});
}
}
main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:text="Add Row"
android:id="@+id/AddRow"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<ScrollView
android:id="@+id/TableScroller"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@id/AddRow"
android:layout_alignParentTop="true" >
<TableLayout
android:id="@+id/Table"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:stretchColumns="0,1,2" />
</ScrollView>
</RelativeLayout>
Изменить: для справки я реализовал решение Romain Guy следующим образом:
В TestActivity.java замените:
// Scrolls to line before last - why?
((ScrollView) findViewById(R.id.TableScroller)).fullScroll(View.FOCUS_DOWN);
с:
// Enqueue the scrolling to happen after the new row has been layout
((ScrollView) findViewById(R.id.TableScroller)).post(new Runnable() {
public void run() {
((ScrollView) findViewById(R.id.TableScroller)).fullScroll(View.FOCUS_DOWN);
}
});
Что отлично работает.
В то время, когда вы выполняете свой fullScroll(), макет еще не выполнен, поэтому ScrollView использует "старый" размер для таблицы. Вместо прямого вызова функции fullScroll() используйте View.post(Runnable).
Найти подсказку выше полезной, вот простая реализация, которая прокручивает ScrollView, чтобы сделать данный дочерний видимым...
a: Подготовьте следующий вспомогательный класс
public class ScrollToTrick implements Runnable {
ScrollView scroller;
View child;
ScrollToTrick(ScrollView scroller, View child) {
this.scroller=scroller;
this.child=child;
}
public void run() {
scroller.scrollTo(0, child.getTop());
}
}
b) назовите его следующим образом
my_scroller.post(new ScrollToTrick(my_scroller,child_to_scroll_to) );