Плавный переход слайда в определенное место

#flutter #animation #widget #transition #slide

#плавный #Анимация #Виджет #переход #слайд

Вопрос:

Я создаю приложение для проверки грамматики, используя flutter, у меня есть вопрос и несколько вариантов, я хочу, чтобы выбор слайдов переходил к пустой части вопроса с анимацией слайда

Например:

Как _ новая школа?

(Вы) (ваш) (это)

и когда я нажимаю на (ваш) виджет выбора перемещается в _ оставляя пустой контейнер

Как (ваша) новая школа?

(Вы) ( ) (это)

Я сделал это с помощью Draggable и DragTarget, и вы можете увидеть это на этих изображениях

изображение 1

изображение 2

но я хочу, чтобы он скользил, когда я нажимаю на него, не перетаскивая

вот часть кода

 class QuestionsScreen extends StatefulWidget {
  QuestionsScreen({Key key}) : super(key: key);

  @override
  _QuestionsScreenState createState() => _QuestionsScreenState();
}

class _QuestionsScreenState extends State<QuestionsScreen> {
  String userAnswer = "_";
  int indexOfDragPlace = QuestionBrain.getQuesitonText().indexOf("_");
  @override
  Widget build(BuildContext context) {
    final screenSize = MediaQuery.of(context).size;
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Container(
              padding: EdgeInsets.all(10),
              color: Colors.white,
              child: Center(
                child: Scrollbar(
                  child: ListView(
                    children: [
                      Center(
                        child: Wrap(
                          children: [

                            ...QuestionBrain.getQuesitonText()
                                .substring(0, indexOfDragPlace)
                                .split(" ")
                                .map((e) => QuestionHolder(
                                      question: e   " ",
                                    )),

                            _buildDragTarget(),

                            ...QuestionBrain.getQuesitonText()
                                .substring(indexOfDragPlace   1)
                                .split(" ")
                                .map((e) => QuestionHolder(
                                      question: e   " ",
                                    )),
                          ],
                        ),
                      )
                    ],
                  ),
                ),
              ),
            ),
     
            Wrap(
              children: [
                ...QuestionBrain.choices.map((choice) {
                  if (choice == userAnswer) {
                    return ChoiceHolder(
                      choice: "",
                      backGroundColor: Colors.black12,
                    );
                  }
                  return DraggableChoiceBox(
                    choice: choice,
                    userAnswer: userAnswer,
                    onDragStarted: () {
                      setState(() {
                        dragedAnswerResult = "";
                      });
                    },
                    onDragCompleted: () {
                      setState(() {
                        userAnswer = choice;
                        setState(() {
                          answerColor = Colors.orange;
                        });
                        print("Called");
                      });
                    },
                  );
                }).toList()
              ],
            ),
          ],
        ),
      ),
    );
  }


  Widget _buildDragTarget() {
    return DragTarget<String>(
      builder: (context, icoming, rejected) {
        return Material(
          child: Container(
            padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
            width: MediaQuery.of(context).size.width * 0.20,
            height: MediaQuery.of(context).size.height * 0.05,
            color: answerColor,
            child: FittedBox(
              child: Text(
                userAnswer,
                style: TextStyle(
                    fontSize: 12,
                    color: Colors.white,
                    fontWeight: FontWeight.bold),
              ),
            ),
          ),
        );
      },
   
      onAccept: (data) {
        userAnswer = data;
        answerColor = Colors.orange;
      },
   
    );
  }

 
}


class DraggableChoiceBox extends StatelessWidget {
  const DraggableChoiceBox({
    Key key,
    this.choice,
    this.userAnswer,
    this.onDragCompleted,
    this.onDragStarted,
  }) : super(key: key);
  final String choice;
  final String userAnswer;
  final Function onDragCompleted;
  final Function onDragStarted;
  @override
  Widget build(BuildContext context) {
    return Draggable(
      onDragCompleted: onDragCompleted,
      data: choice,
      child: ChoiceHolder(choice: choice),
      feedback: Material(
        elevation: 20,
        child: ChoiceHolder(
          choice: choice,
          margin: 0,
        ),
      ),
      childWhenDragging: ChoiceHolder(
        choice: "",
        backGroundColor: Colors.black12,
      ),
      onDragStarted: onDragStarted,
    );
  }
}
  

Комментарии:

1. Пожалуйста, поделитесь частью вашего кода, который вы уже пробовали.

2. @HasilT Я добавил часть кода, вам нужно больше разъяснений?

Ответ №1:

Вы можете использовать overlays аналогично тому, как Hero работают виджеты, вот «неотшлифованный» пример:

 import 'package:flutter/material.dart';

class SlideToPosition extends StatefulWidget {
  @override
  _SlideToPositionState createState() => _SlideToPositionState();
}

class _SlideToPositionState extends State<SlideToPosition> {
  GlobalKey target = GlobalKey();

  GlobalKey toMove = GlobalKey();
  double dx = 0.0, dy = 0.0, dxStart = 0.0, dyStart = 0.0;
  String choosedAnswer = '', answer = 'answer', finalAnswer = '';

  OverlayEntry overlayEntry;

  @override
  void initState() {
    overlayEntry = OverlayEntry(
      builder: (context) => TweenAnimationBuilder(
        duration: Duration(milliseconds: 500),
        tween:
            Tween<Offset>(begin: Offset(dxStart, dyStart), end: Offset(dx, dy)),
        builder: (context, offset, widget) {
          return Positioned(
            child: Material(
                child: Container(
                    color: Colors.transparent,
                    height: 29,
                    width: 100,
                    child: Center(child: Text(choosedAnswer)))),
            left: offset.dx,
            top: offset.dy,
          );
        },
      ),
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            SizedBox(
              height: 20,
            ),
            Row(
              children: [
                Text('text'),
                Container(
                  key: target,
                  height: 30,
                  width: 100,
                  child: Center(child: Text(finalAnswer)),
                  decoration:
                      BoxDecoration(border: Border(bottom: BorderSide())),
                ),
                Text('text')
              ],
            ),
            SizedBox(
              height: 20,
            ),
            GestureDetector(
              child: Container(
                  height: 30,
                  width: 100,
                  color: Colors.blue[200],
                  child: Center(child: Text(answer, key: toMove))),
              onTap: () async {
                setState(() {
                  answer = '';
                });
                RenderBox box1 = target.currentContext.findRenderObject();

                Offset targetPosition = box1.localToGlobal(Offset.zero);

                RenderBox box2 = toMove.currentContext.findRenderObject();
                Offset toMovePosition = box2.localToGlobal(Offset.zero);
                
                setState(() {
                  answer = '';
                  choosedAnswer = 'answer';
                });
                dxStart = toMovePosition.dx;
                dyStart = toMovePosition.dy;
                dx = targetPosition.dx;
                dy = targetPosition.dy;

                Overlay.of(context).insert(overlayEntry);
                setState(() {});

                await Future.delayed(Duration(milliseconds: 500));

                overlayEntry.remove();
                setState(() {
                  finalAnswer = 'answer';
                });
              },
            ),
          ],
        ),
      ),
    );
  }
}

  

Извините за плохое именование переменных 🙂

Комментарии:

1. Спасибо, приятель, ты очень помог