недавно вUIMovementЯ увидел относительно крутой эффект страницы входа, как показано ниже:
Я думал, что это круто, поэтому я сам это реализовал, а эффект следующий:
Ниже приводится пошаговый анализ того, как это сделать.
анализ спроса
Прежде всего, старая рутина, посмотрите, что нужно сделать:
- Прежде всего, наше самое очевидное требование - нажать «Регистрация», чтобы открыть диалоговое окно.
- После того, как диалоговое окно всплывает, содержимое диалогового окна появляется после задержки в течение определенного периода времени.
- Текст описания в Диалоге имеет два цвета
- Нажатие кнопки «Принять» изменит цвет, чтобы сжаться и вернуться обратно, и отобразится значок «ОК».
- При нажатии кнопки «Принять» другой текст в диалоговом окне становится «белой маской».
- Кнопка "Принять" После окончания анимации закрыть текущий диалог и переместить логотип вверх
- Перейти на вторую страницу, текст всплывает в волнистой форме
- После появления текста покажите диалоговое окно и всплывающую клавиатуру.
приступить к реализации
Потребности понятны, и ниже приведен эффект пошаговой реализации.
1. Нажмите «Зарегистрироваться», чтобы открыть диалоговое окно.
Вот на что нам нужно обратить внимание:
в нашем использованииshowModalBottomSheet
, фон по умолчанию белый, что означает, что закругленные углы, которые мы установили сами, бесполезны.
Так что дайте этомуBottomSheet
Фон, этот параметр находится вshowModalBottomSheet
Метод имеет:
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (context) {
Future.delayed(Duration(milliseconds: 50), () {
_animationController.forward();
});
return AnimatedUserAgreement(
animation: _animation,
);
});
)
установить одинbackgroundColor
Ничего страшного.
2. После открытия диалогового окна содержимое диалогового окна появится после некоторой задержки.
Здесь я написал"AnimatedWidget", Одновременно анимируйте прозрачность и положение виджета в диалоговом окне:
return Container(
height: 270,
padding: EdgeInsets.all(30),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30), color: Colors.white),
child: Opacity(
opacity: _opacityTween.evaluate(animation),
child: Stack(
children: <Widget>[
SingleChildScrollView(
child: Container(
child: UserAgreementDialog(),
margin: EdgeInsets.only(top: _offsetTween.evaluate(animation)),
),
)
],
),
),
);
Внимательные студенты могут заметить, что в приведенном выше коде есть некоторые проблемы:
зачем добавлять одинSingleChildScrollView
?
Потому что эффект анимации, который я использую для изменения положения здесь,"Динамически изменить значение маржи контейнера",
Поэтому, если вы не используете ScrollView, он переполнится.
3. Текст описания в Диалоге имеет два цвета
Требование иметь два цвета относительно просто, и это можно сделать с помощью "TextSpan".
Код выкладывать не буду.
4. Нажмите кнопку «Принять», она изменит цвет, уменьшится и вернется в исходное состояние, а также отобразится значок «ОК».
Дело в том, что эта функция относительно сложна, но пока мы понимаем требования, ее относительно просто написать.
Во-первых, давайте разберем эту особенность:
- Нажмите кнопку, когда вы приедете
- После нажатия он вернется к исходному цвету и сожмется до круга.
- После превращения в круг анимационный эффект показывает значок ок
Все равно шаг за шагом.
1. Изменение цвета при нажатии кнопки
Эту функцию не нужно рассматривать слишком много, так как есть жест клика, его необходимо использовать.GestureDetector
,
затем используйтеGestureDetector
изonTapDown
параметр, который вызывается при "нажатии":
onTapDown: (d) {
setState(() {
btnColor = btnColors[1];
});
Ничего лишнего, просто меняем цвет кнопки.
2. После нажатия он вернется к исходному цвету и сожмется в круг.
Как обрабатывать пост-клик? Или без кликов?
GestureDetector
Это также помогло нам упаковать его:
- onTapUp: Обратный вызов, когда кран поднят
- onTapCancel: Обратный вызов при отмене клика
Сначала мы обрабатываем отмену клика:
onTapCancel: () {
setState(() {
btnColor = btnColors[0];
});
}
Просто измените цвет обратно.
Тогда обработайте логику при подъеме, там тоже две логики при подъеме:
- Кнопка сожмется в круг
- Когда он сожмется до круга, появится значок ОК.
Прежде всего, поговорим о первом пункте:
Когда он сводится к кругу, возникает эффект отскока, поэтому его нельзя использоватьAnimatedContainer
Это должно быть использованоAnimation
иметь этот эффект.
Так что я использовалAnimatedBuilder
чтобы обернуть этот виджет.
Затем произнесите второй пункт:
Как вывести значок ОК при сжатии в круг?
мы можем использоватьIndexStack
, переключить индекс при запуске сжимать анимацию, потому что состояние масштабирования значка ок в начале равно 0, поэтому на странице нет значка, который нам удобно потом анимировать.
Код виджета выглядит следующим образом:
AnimatedBuilder(
animation: _widthAnimation,
builder: (BuildContext context, Widget child) {
return Container(
width: _widthAnimation.value,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(40)),
color: btnColor),
margin: EdgeInsets.only(top: btnMargin),
height: btnHeight,
child: IndexedStack(
alignment: Alignment.center,
index: index,
children: <Widget>[
Text(
'Accepteer',
style: TextStyle(fontSize: 18),
),
ScaleTransition(
scale: _scaleTween.animate(_animation),
child: Image.asset(
'images/ok.png',
width: 35,
height: 35,
),
)
],
),
);
},
),
5. При нажатии кнопки «Принять» другой текст в диалоговом окне будет «белой маской».
Это тоже очень просто,Container
По умолчанию есть один параметр:foregroundDecoration
, нам нужно только установить цвет, который мы хотим замаскировать в этом параметре.
Тем не менее, следует отметить, что если цвет маски, используемый в начале, является "прозрачным цветом", то он станет черным в целом. Конкретную причину этого я не изучал. Кто знает, может мне сказать.
Таким образом, эффект после нажатия кнопки завершается, и код выглядит следующим образом:
onTapUp: (d) {
Future.delayed(Duration(milliseconds: 60), () {
setState(() {
foregroundColor = Colors.white70;
btnColor = btnColors[0];
index = 1;
});
_widthController.forward();
Future.delayed(Duration(milliseconds: 200), () {
_controller.forward().then((va) {
Navigator.pop(context);
});
});
});
}
6. После окончания анимации закрыть текущий диалог и переместить логотип вверх
Это относительно просто, нам нужно только поместить один над логотипом.AnimatedContainer
,
Затем проследите, было ли закрыто диалоговое окно, и если да, отрегулируйте значение поля.
код показывает, как показано ниже:
setState(() {
logoMargin = 100;
});
Таким образом, диалоговое окно будет иметь нисходящую анимацию, а логотип будет двигаться вверх, что позволит достичь нужного нам эффекта.
7. Перейти на вторую страницу, текст всплывает волнами
Как сделать так, чтобы текст всплывал в волнистой форме?
Первое, о чем мы должны думать, это анимация, потому что только анимация имеет такой эффект отскока.
Так много текстов, каждый нужно анимировать?
Ответ положительный.
Теперь, когда мы знаем, мы можем делать это только шаг за шагом.
Как видите, каждый текст меняется с прозрачного на непрозрачный, а также меняет свое положение,
Итак, давайте сначала завершим одинAnimatedWidget
.
код показывает, как показано ниже:
class AnimatedStrWidget extends AnimatedWidget {
final Tween<double> _opacityTween = Tween(begin: 0, end: 1);
final Tween<Offset> _offsetTween =
Tween(begin: Offset(0, 3), end: Offset(0, 0));
final Widget child;
AnimatedStrWidget(
{Key key, @required Animation<double> animation, @required this.child})
: super(key: key, listenable: animation);
@override
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Opacity(
opacity: _opacityTween.evaluate(animation) < 0
? 0
: _opacityTween.evaluate(animation) > 1
? 1
: _opacityTween.evaluate(animation),
child: SlideTransition(
position: _offsetTween.animate(animation),
child: child,
),
);
}
}
Здесь также следует отметить два момента:
- Прозрачность не может иметь отрицательное число и не может быть больше 1, потому что наш эффект должен иметь эффект отскока, поэтому нам нужно судить.
- Tween
Значение здесь кратно всей высоте, поэтому не думайте, что это значение в пикселях.
После упаковки мы можем играть счастливо:
void startAnim() async {
for (int i = 0; i < strs.length; i++) {
Future.delayed(
Duration(
milliseconds: i * 100,
), () {
_strController[i].forward();
});
}
}
Текстовый всплывающий эффект времени 600 мс, установите здесь, чтобы делать фильм каждые 100 мс,
Этот эффект лучше, больше похож на волнистую поп-музыку.
8. После появления текста отобразите диалоговое окно и всплывающую клавиатуру.
Мы все должны знать об активно всплывающей клавиатуре, использоватьFocusNode
,
Здесь нам нужно только определить, когда последняя анимация закончилась, затем открыть скрытую клавиатуру, снова открыть клавиатуру, и все в порядке.
код показывает, как показано ниже:
_strPositionAnimation[strs.length - 1].addStatusListener((status){
if(status == AnimationStatus.completed){
setState(() {
opacity = 1;
FocusScope.of(context).requestFocus(myFocusNode);
});
}
});
Суммировать
На реализацию этой странички у меня ушла целая ночь, и надо сказать, дел еще много.
Добиться такой классной страницы входа еще сложнее.
То, чего я здесь добился, не идеально, и кажется немного «спешащим» по сравнению с исходным изображением.
Но это не имеет значения, это просто вопрос изменения продолжительности анимации.
В этом же предложении разберитесь в нуждах и сделайте все.
Код загружен на GitHub:GitHub.com/web1209/…
Кроме того, я лично создал «Flutter Exchange Group», и я могу добавить свой личный WeChat «17610912320», чтобы присоединиться к группе.
Рекомендуемое чтение:
Flutter | WReorderList Компонент, который может указать позицию обмена двух элементов
Flutter | Как реализовать виджет с эффектом диффузии водной ряби