android Flutter动画放大图像

mgdq6dx1  于 2023-03-27  发布在  Android
关注(0)|答案(2)|浏览(139)

我想在Flutter中的年龄输入屏幕上添加一些很酷的东西,我想做的主要方式是当年龄滑块增加时,图像会增长,当年龄滑块减少时,图像会缩小。这是一个非常简单的动画,我不知道如何实现,如果有人回答这个问题,我将不胜感激。下面是我当前年龄屏幕的截图(有一个很大的空间用于增长图像):(检查下面的图像),和截图的代码.谢谢!
编辑:一个对我来说非常有帮助的大奖励是随着用户增加滑块,动画从一个孩子变成一个成年人再变成一个老人。所以图像从一个孩子开始,变大,图像变成一个成年人,然后缩小一点,变成一个老年人。如果这是成功的,我会非常感激。再次感谢!

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen1.dart';
import 'package:workout_app/Screens/Components/Sign_Up_Screens/screen3.dart';

class screen2 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => Main();
}

class Main extends State<screen2> {
  void returnScreen(context) {
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        fullscreenDialog: true,
        builder: (context) => screen1(),
      ),
    );
  }

    
  @override
  void initState() {
    loadData();
    super.initState();
  }

  @override
  void dispose() {
    super.dispose();
  }
  

  @override
  int age = 10;
  bool nextValid = false;

  void toast(String text) {
    final scaffold = ScaffoldMessenger.of(context);
    scaffold.showSnackBar(
      SnackBar(
        width: MediaQuery.of(context).size.width * .5,
        behavior: SnackBarBehavior.floating,
        content: Text(text),
        duration: const Duration(seconds: 1),
        elevation: 10,
      ),
    );
  }

  void submitData() async {
    if(nextValid == false) {
      toast('Please input your age');
      return;
    }
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setInt('age', age);
    Navigator.of(context).pushReplacement(
      MaterialPageRoute(
        fullscreenDialog: true,
        builder: (context) => SingleSelectListViewWithLogo(items : ['Tone Up - You want visible muscles with as little mass as possible and a low body fat percentage', 'Bulk Up - You want large, defined muscles, with a low percentage of body fat', 'Get Jacked - You want to lift an insane amount of weight and don\'t care about body fat or muscle definition']),
      ),
    );
  }

  void loadData() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    try {
      int? x = prefs.getInt('age');
      print(x);
      if(x != null) {
        setState(() => {age = x, nextValid = true});
      }
    } catch (Exception){
      //continue;
    }
  }

  Widget build(BuildContext context) {
    Size size = MediaQuery.of(context).size;
    return Material(
      child: Scaffold(
      body: 
        Container (
          decoration: const BoxDecoration(color: Color.fromARGB(255, 46, 46, 46)),
          height: size.height,
          width: double.infinity,
          child: Stack(
            children: <Widget> [
              Positioned (
                top: size.height * .34,
                height: size.height * .6,
                width: size.width * .9,
                left: size.width * .05,
                child: Container (
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(15),
                    color: Color.fromARGB(255, 73, 73, 73),
                  ),
                ),
              ),
              Positioned(
                top: size.height * .06,
                left: size.width * .03,
                child: InkWell(
                  onTap: () {
                    returnScreen(context);
                  },
                  child: Image.asset(
                    alignment: Alignment.topLeft,
                    "assets/images/whitebackarrow.png",
                    width: size.width * .07,
                  ),
                ),
              ), 
              Positioned(
                top: size.height * .09,
                left: size.width * .35,
                child: const Text(
                  style: TextStyle(fontSize: 50, color: Color.fromARGB(255, 255, 255, 255), fontWeight: FontWeight.bold),
                  'Next,'
                )
              ),
              Positioned(
                top: size.height * .19,
                left: size.width * .06,
                child: const Text(
                  style: TextStyle(fontSize: 25, color: Color.fromARGB(255, 255, 255, 255)),
                  'Lets customize your workout!'
                )
              ),
              Positioned(
                top: size.height * .38,
                left: size.width * .13,
                child: const Text(
                  style: TextStyle(fontSize: 25, color: Color.fromARGB(255, 0, 0, 0), fontWeight: FontWeight.bold),
                  'What\'s your current age?'
                )
              ),
              Positioned (
                top: size.height * .7,
                left: size.width * .1,
                child: SliderTheme(
                  data: const SliderThemeData(
                    trackHeight: 30,
                    inactiveTrackColor: Color.fromARGB(255, 160, 160, 160),
                    activeTrackColor: Color.fromARGB(255, 40, 39, 39),
                    thumbColor: Colors.black,
                    disabledActiveTrackColor: Colors.black,
                    disabledInactiveTrackColor: Colors.black12,
                    thumbShape: RoundSliderThumbShape(enabledThumbRadius: 25.0),
                  ),
                  child: Container (
                    width: size.width * .8,
                    child: Slider(
                      label: "Select Age",
                      value: age.toDouble(),
                      onChanged: (value) {
                        setState(() {
                          age = value.toInt();
                          nextValid = true;
                        });
                      },
                      min: 10,
                      max: 99,
                    )
                  )
                )
              ),
              Positioned (
                top: size.height * .605,
                left: size.width * .25,
                child: Text(
                  age.toString(),
                  style: const TextStyle(
                    fontSize: 50.0,
                    fontWeight: FontWeight.bold
                  ),
                ),
              ),
              Positioned (
                top: size.height * .64,
                left: size.width * .42,
                child: const Text (
                  'years old',
                  style: TextStyle(
                    fontSize: 25.0,
                  ),
                )
              ),
              Positioned(
                top: size.height * .825,
                left: size.width * .1,
                child: SizedBox(
                  width: size.width * .8,
                  height: size.height * .08,
                  child: ElevatedButton(
                    style: ButtonStyle(                  
                      backgroundColor: MaterialStateProperty.all<Color>(!nextValid ? Color.fromRGBO(69, 75, 85, 1) : Color.fromARGB(255, 23, 100, 22)),
                    ),
                    child: const Text('Continue',
                      style: TextStyle(fontSize: 20),
                    ),
                    onPressed: () async {
                      submitData();
                    },
                  ),
                ),
              ),
            ]
          )
        )
      )
    );
  }
}

x1c 0d1x。这是屏幕的代码:

r7s23pms

r7s23pms1#

回答有点晚了。我也是这么做的。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    theme: ThemeData(useMaterial3: true),
    home: const MyPage(),
  ));
}

class MyPage extends StatelessWidget {
  const MyPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Slider Example'),
      ),
      body: const Center(
        child: Card(
          child: CustomSlider(),
        ),
      ),
      bottomSheet: SafeArea(
        child: BottomSheet(
            onClosing: () {},
            builder: (ctx) {
              return const Padding(
                padding: EdgeInsets.symmetric(horizontal: 40, vertical: 20),
                child: Text(
                    'ℹ️ The gender choices and corresponding emojis shown here are for demonstration purpose only and does not reflect my view in any manner.'),
              );
            }),
      ),
    );
  }
}

class CustomSlider extends StatefulWidget {
  const CustomSlider({
    super.key,
  });

  @override
  State<CustomSlider> createState() => _CustomSliderState();
}

class _CustomSliderState extends State<CustomSlider> {
  var _age = 21;
  final _data = {
    const IntRange(0, 6): {'m': '👶🏻', 'f': '👶🏻'},
    const IntRange(7, 18): {'m': '👦', 'f': '👧'},
    const IntRange(19, 60): {'m': '🧔‍♂️', 'f': '👩'},
    const IntRange(61, 100): {'m': '👴', 'f': '👵'},
  };
  var _gender = 'f';

  @override
  Widget build(BuildContext context) {
    final range = _data.keys.firstWhere((range) => _age.within(range));
    final text = _data[range]![_gender]!;
    final size = 72 + (_age - range.start) / (range.end - range.start) * 50;

    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Text(
          'What\'s your current age?',
          style: Theme.of(context).textTheme.headlineMedium,
        ),
        const SizedBox(
          height: 20,
        ),
        Center(
          child: SizedBox.square(
            dimension: 300,
            child: Center(
              child: AnimatedSwitcher(
                duration: const Duration(milliseconds: 700),
                child: Text(
                  key: ValueKey(text),
                  text,
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: size),
                ),
              ),
            ),
          ),
        ),
        Slider(
          value: _age.toDouble(),
          onChanged: _onAgeChanged,
          min: 0,
          max: 100,
          divisions: 101,
        ),
        const SizedBox(
          height: 20,
        ),
        Text(
          'Your current age $_age',
          style: const TextStyle(fontSize: 24),
        ),
        const SizedBox(
          height: 20,
        ),
        Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Radio<String>(
              value: 'm',
              groupValue: _gender,
              onChanged: _onGenderChanged,
            ),
            const Text('Male'),
            const SizedBox(
              width: 20,
            ),
            Radio<String>(
              value: 'f',
              groupValue: _gender,
              onChanged: _onGenderChanged,
            ),
            const Text('Female'),
          ],
        )
      ],
    );
  }

  void _onAgeChanged(double value) {
    _age = value.toInt();
    setState(() {});
  }

  void _onGenderChanged(newValue) {
    _gender = newValue!;
    setState(() {});
  }
}

@immutable
class IntRange {
  final int start;
  final int end;

  const IntRange(
    this.start,
    this.end,
  );

  @override
  String toString() => 'IntRange(start: $start, end: $end)';

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;

    return other is IntRange && other.start == start && other.end == end;
  }

  @override
  int get hashCode => start.hashCode ^ end.hashCode;
}

extension Range on int {
  bool within(IntRange range) {
    return this >= range.start && this <= range.end;
  }
}

演示:https://youtube.com/shorts/CyymV-GQvj4?feature=share
PS:我知道已经有一个公认的答案了。我想为什么不在这里分享一下,因为解决方案已经准备好了。

ui7jx7zq

ui7jx7zq2#

根据你的代码,你可以只拥有一个Image.assetheight属性。使用age状态作为图像的高度。你可以在这里做一些简单的数学运算,你可以把年龄乘以一些数字来适合你喜欢的图像。

Image.asset(
  "assets/images/bqubique.png",
  height: age.toDouble(),
),

为了使图像动画化,我将使用AnimatedContainer检查它,但在这种情况下,您需要重新修改上述解决方案:

AnimatedContainer(
  duration: const Duration(seconds: 1),
  //Choose which curve you want to have here, I randomly selected bounceIn (refer to Curves class documentation)
  curve: Curves.bounceIn,
  height: age.toDouble(),
  child: Image.asset(
    "assets/images/bqubique.png",
  ),
)

编辑:只是添加更多细节:
AnimatedContainer允许您使用给定的属性为Container设置动画(heightwidthdecorationcolor等)。当插入状态变量时(在本例中为age变量)作为这些参数之一的输入,AnimatedContainer会根据输入的变化自动动画化它的属性。它需要Duration才能知道动画运行需要多长时间。通过包含curve属性,您还可以添加比线性动画更精美的动画。
要了解有关动画的更多信息,请参阅Introduction to animations
要了解有关AnimatedContainer的更多信息,请参阅AnimatedContainer class
要了解有关Curves的更多信息,请参阅Curves class

相关问题