HorizontalScrollView scrollTo не прокручивается выше исходной ширины представления

У меня есть пользовательское представление, содержащее HorizontalScrollView. Ширина представления прокрутки равна match_parent, а ширина его дочерних элементов изначально устанавливается программно на основе значения атрибута пользовательского представления. В какой-то момент ширина дочерних элементов прокрутки обновляется (увеличивается) программно. Проблема в том, что после обновления метод scrollTo по-прежнему не может прокручиваться выше исходного значения ширины (то же самое для scrollBy).

Окружающий вид (пользовательский) имеет отступы слева и справа, равные половине экрана, если это уместно.

Пример:

  • Начальная ширина дочерних элементов HorizontalScrollView: 1000;
  • Родительская ширина HorizontalScrollView: 1080;
  • Отступ слева/справа HorizontalScrollView = 540;
  • Ширина новых дочерних элементов HorizontalScrollView: 2000;
  • прокрутить до (1100, 0) = прокрутить до (1000, 0); ‹---- вот проблема

Соответствующий код:

Инициализация пользовательского представления:

private void init(AttributeSet attrs, int defStyle) {
    inflate(getContext(), R.layout.timeline_view, this);

    // Load attributes
    final TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.TimelineView, defStyle, 0);

    m_timelineInitialLength = a.getDimension(R.styleable.TimelineView_timelineInitialLength, DEFAULT_LENGTH);

    a.recycle();

    DisplayMetrics displayMetrics = new DisplayMetrics();
    ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    LinearLayout timelineWidget = findViewById(R.id.timeline_widget);
    int horizontalPadding = displayMetrics.widthPixels / 2;
    timelineWidget.setPadding(horizontalPadding, 0, horizontalPadding, 0);

    m_horizontalScrollView = findViewById(R.id.scroll_view);
    m_horizontalScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
        @Override
        public void onScrollChanged() {
            m_currentScrollX = m_horizontalScrollView.getScrollX();
        }
    });
    m_currentScrollX = m_horizontalScrollView.getScrollX();

    update(m_timelineInitialLength, m_timelineInitialStepWidth, m_currentScrollX);
}

Update и scrollTo (этот метод вызывается также в конце инициализации. m_rulerView и m_timelineLayout — дочерние элементы HorizontalScrollView):

private void update(float timelineLength, float timelineStepWidth, int currentScrollX) {
    m_rulerView = findViewById(R.id.ruler);
    m_rulerView.setIndicator(null);
    m_rulerView.getLayoutParams().width = (int) timelineLength;
    m_rulerView.requestLayout();

    m_timelineLayout = findViewById(R.id.timeline);
    m_timelineLayout.getLayoutParams().width = (int) timelineLength;
    m_timelineLayout.requestLayout();

    m_horizontalScrollView.scrollTo(currentScrollX, 0);
}

person Davide Visentin    schedule 26.09.2019    source источник


Ответы (1)


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

Я решил использовать обходной путь, выполнив scrollTo через некоторое время:

new Handler().postDelayed(() -> ((Activity) getContext()).runOnUiThread(() -> m_horizontalScrollView.scrollTo(currentScrollX, 0)), 200);

Я все еще открыт для лучших решений.

person Davide Visentin    schedule 26.09.2019