Я пытаюсь реализовать дизайн, который выглядит так:
В примере currentItem в середине имеет размер 19
, а его opacity
— 100%. Второй элемент ниже/выше имеет размер 13
с opacity
50%, а третий элемент имеет размер 9
и opacity
25%.
Как я могу реализовать что-то подобное с помощью Flutter? Я пробовал несколько вещей, например ListWheelScrollView
, но я не мог получить желаемый дизайн.
Еще одно требование: currentItem должен быть tappable
.
Есть идеи, как я могу это сделать?
Решением может быть использование CupertinoPicker
для достижения желаемого дизайна.
Например, используя StatefulWidget
для обновления и получения currentIndex
:
static const double _containerHeight = 500;
int currentIndex = 0;
@override
Widget build(BuildContext context) {
return SizedBox(
height: _containerHeight,
child: CupertinoPicker.builder(
itemExtent: _containerHeight / 3,
diameterRatio: 20,
useMagnifier: false,
selectionOverlay: null,
onSelectedItemChanged: (value) => setState(() => currentIndex = value),
itemBuilder: (context, index) {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
AnimatedDefaultTextStyle(
duration: const Duration(milliseconds: 200),
style: TextStyle(fontSize: getFontSizeFromIndex(index)),
child: Text(
'Das ist ein Text',
style: TextStyle(
color:
Colors.white.withOpacity(getOpacityFromIndex(index))),
),
),
],
);
},
),
);
}
double getFontSizeFromIndex(int index) => index == currentIndex
? 19
: index == currentIndex - 1 || index == currentIndex + 1
? 13
: 9;
double getOpacityFromIndex(int index) => index == currentIndex
? 1
: index == currentIndex - 1 || index == currentIndex + 1
? .5
: .25;
Чтобы идти дальше, вы должны учитывать:
debouncing
onSelectedItemChanged
для предотвращения неправомерных перестроек;ScrollController
, и сделайте несколько линейных интерполяций, чтобы сделать анимацию более плавной.Вот результат:
Кроме того, я знаю, что упомянул конкретные значения, на которые следует изменить fontSize и opacity. Но в идеальной анимации я хотел бы, чтобы оба значения динамически менялись в зависимости от каждого пикселя положения прокрутки.
Вы можете изменить DiameterRatio на 1.0, чтобы удалить этот эффект «отрезания». Вы также можете поиграть с offAxisFraction и itemExtent, чтобы получить желаемый эффект. Для идеальной анимации советую использовать CustomScrollController.
никогда не думал о
CuperthinoPicker
! Выглядит многообещающе. Моя самая большая проблема с этим решением заключается в том, что центральный элемент обрезается при анимации вдали от центра. Есть ли способ предотвратить это?