Flutter PageTransitionSwitcher का उपयोग करके टैब की स्थिति नहीं रख सकता है

Nov 28 2020

मैं एनिमेशन पैकेज के साथ संघर्ष कर रहा हूं और मैं बॉटनवैनरिगेशन के साथ एनीमेशन का उपयोग करना चाहता हूं। एनीमेशन के बिना, मैं IndexedStack का उपयोग करके अपने राज्य को बचा सकता हूं। यदि मैं PageTransitionSwitcher के अंदर IndexedStack लपेटता हूं तो यह काम नहीं करता है। विशेष रूप से:

  • एनिमेशन नहीं दिखा रहे हैं लेकिन राज्य रखा गया है
  • यदि मैं अपने IndexedStack की प्रमुख संपत्ति का उपयोग करता हूं, तो एनिमेशन दिखा रहे हैं, लेकिन राज्य काम नहीं कर रहा है।

मेरे द्वारा यह कैसे किया जा सकता है? मुझे नहीं पता कि चाबियाँ कैसे सेट करें। आपका बहुत बहुत धन्यवाद!!

class MainScreen extends StatefulWidget {
  static String id = 'loading_screen';

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

class _MainScreenState extends State<MainScreen> {
  int _selectedPage = 0;
  List<Widget> pageList = List<Widget>();

  @override
  void initState() {
    pageList.add(PrimoTab());
    pageList.add(SecondoTab());
    pageList.add(TerzoTab());
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom tab'),
      ),
      body: PageTransitionSwitcher(
        transitionBuilder: (child, primaryAnimation, secondaryAnimation) {
          return SharedAxisTransition(
            animation: primaryAnimation,
            secondaryAnimation: secondaryAnimation,
            child: child,
            transitionType: SharedAxisTransitionType.horizontal,
          );
        },
        child: IndexedStack(
          index: _selectedPage,
          children: pageList,
          //key: ValueKey<int>(_selectedPage), NOT WORKING
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.directions_car),
            label: 'First Page',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.airplanemode_active),
            label: 'Second Page',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.directions_bike),
            label: 'Third Page',
          ),
        ],
        currentIndex: _selectedPage,
        selectedItemColor: Colors.lightGreen,
        unselectedItemColor: Colors.lightBlueAccent,
        onTap: _onItemTapped,
      ),
    );
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedPage = index;
    });
  }
}

प्रत्येक टैब दो टेक्स्ट विजेट, एक बटन और एक टेक्स्ट काउंटर (प्रत्येक टैब की स्थिति का परीक्षण करने के लिए) के साथ एक कॉलम है:

class PrimoTab extends StatefulWidget {

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

class _PrimoTabState extends State<PrimoTab> {
  int cont = -1;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(
              'TAB 1 - TEXT 1',
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(
              'TAB 1 - TEXT 2',
            ),
          ),
          FlatButton(
            onPressed: () {
              setState(() {
                cont++;
              });
            },
            child: Text("CLICK"),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text(
              'Valore contatore $cont',
            ),
          ),
        ],
      ),
    );
  }
}

अद्यतन 1: बस का उपयोग कर

pageList[_selectedPage],

के बजाय

IndexedStack(
...
)

लेकिन काम नहीं कर रहा है (एनिमेशन ठीक है लेकिन राज्य नहीं रखा गया है)

समाधान के साथ 2 अद्यतन (main.dart):

void main() {
  runApp(
    MaterialApp(
      home: MainScreen(),
    ),
  );
}

class MainScreen extends StatefulWidget {
  static String id = 'loading_screen';

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

class _MainScreenState extends State<MainScreen> {
  int _selectedPage = 0;
  List<Widget> pageList = List<Widget>();

  @override
  void initState() {
    pageList.add(PrimoTab());
    pageList.add(SecondoTab());
    pageList.add(TerzoTab());
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Bottom tab'),
      ),
      body: AnimatedIndexedStack(
        index: _selectedPage,
        children: pageList,
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.directions_car),
            label: 'First Page',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.airplanemode_active),
            label: 'Second Page',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.directions_bike),
            label: 'Third Page',
          ),
        ],
        currentIndex: _selectedPage,
        selectedItemColor: Colors.lightGreen,
        unselectedItemColor: Colors.lightBlueAccent,
        onTap: _onItemTapped,
      ),
    );
  }

  void _onItemTapped(int index) {
    setState(() {
      _selectedPage = index;
    });
  }
}

class AnimatedIndexedStack extends StatefulWidget {
  final int index;
  final List<Widget> children;

  const AnimatedIndexedStack({
    Key key,
    this.index,
    this.children,
  }) : super(key: key);

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

class _AnimatedIndexedStackState extends State<AnimatedIndexedStack>
    with SingleTickerProviderStateMixin {
  AnimationController _controller;
  Animation<double> _animation;
  int _index;

  @override
  void initState() {
    _controller = AnimationController(
      vsync: this,
      duration: Duration(milliseconds: 150),
    );
    _animation = Tween(begin: 0.0, end: 1.0).animate(
      CurvedAnimation(
        parent: _controller,
        curve: Curves.ease,
      ),
    );

    _index = widget.index;
    _controller.forward();
    super.initState();
  }

  @override
  void didUpdateWidget(AnimatedIndexedStack oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.index != _index) {
      _controller.reverse().then((_) {
        setState(() => _index = widget.index);
        _controller.forward();
      });
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Opacity(
          opacity: _controller.value,
          child: Transform.scale(
            scale: 1.015 - (_controller.value * 0.015),
            child: child,
          ),
        );
      },
      child: IndexedStack(
        index: _index,
        children: widget.children,
      ),
    );
  }
}

जवाब

1 yellowgray Nov 29 2020 at 06:27

आपकी स्थिति को ठीक करने के कुछ तरीके हैं। उनमें से कोई भी पूरी तरह से सरल नहीं है और पहले से ही यहाँ और यहाँ बहुत चर्चा है , IndexedStackसाथ विलय करने की कोशिश कर रहा है PageTransitionSwitcher। अब तक कोई समाधान नहीं मैंने देखा।

मैं इसे प्राप्त करने के लिए संभावित तरीके एकत्र करता हूं:

  1. राज्य को कहीं और स्टोर करें और बच्चे को पास करें। मैंने नहीं देखा है कि कोई भी विधि PageTransitionSwitcherबाल विजेट के पुनर्निर्माण से रोक सकती है । यदि आप चाइल्ड विजेट पुनर्निर्माण नहीं करते हैं , तो ऐसा करने के लिए यह सबसे सीधा फॉरवर्ड तरीका हो सकता है।

  2. IndexedStackएनीमेशन के साथ कस्टम का उपयोग करें । यह और यह पसंद है । यह IndexStack में इस सुविधा के साथ अच्छी तरह से काम करता है कि बच्चे पुनर्निर्माण नहीं करेंगे, लेकिन एनीमेशन उतना अच्छा नहीं है PageTransitionSwitcherऔर यह केवल एक बार में 1 विजेट दिखा सकता है।