颤动,水平导航

时间:2018-06-30 12:05:45

标签: android flutter

在Codelab英语单词示例中... https://flutter.io/get-started/codelab/ iOS导航过渡是水平 ..,就像您希望Segue在UINavigationController中起作用一样。从右到左...流行音乐从左到右。
ANDROID,相同的示例是VERTICAL,从下至上。持久性有机污染物从上到下。
我的问题...我应如何在ANDROID中强制进行 Horizo​​ntal 过渡,使其表现得像iOS?我怀疑我将不得不使用 MaterialPageRoute

    /*
Nguyen Duc Hoang(Mr)
Programming tutorial channel:
https://www.youtube.com/c/nguyenduchoang
Flutter, React, React Native, IOS development, Swift, Python, Angular
* */
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

//Define "root widget"
void main() => runApp(new MyApp());//one-line function
//StatefulWidget
class RandomEnglishWords extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new RandomEnglishWordsState();//return a state's object. Where is the state's class ?
  }
}
//State
class RandomEnglishWordsState extends State<RandomEnglishWords>{
  final _words = <WordPair>[];//Words displayed in ListView, 1 row contains 1 word
  final _checkedWords = new Set<WordPair>();//set contains "no duplicate items"
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    //Now we replace this with a Scaffold widget which contains a ListView
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("List of English words"),
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list),
              onPressed: _pushToSavedWordsScreen)
        ],
      ),
      body: new ListView.builder(itemBuilder: (context, index) {
        //This is an anonymous function
        //index = 0, 1, 2, 3,...
        //This function return each Row = "a Widget"
        if (index >= _words.length) {
          _words.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_words[index], index);//Where is _buildRow ?
      }),
    );
  }
  _pushToSavedWordsScreen() {
//    print("You pressed to the right Icon");
    //To navigate, you must have a "route"
    final pageRoute = new MaterialPageRoute(builder: (context) {
      //map function = Convert this list to another list(maybe different object's type)
      //_checkedWords(list of WordPair) => map =>
      // converted to a lazy list(Iterable) of ListTile
      final listTiles = _checkedWords.map( (wordPair) {
        return new ListTile(
          title: new Text(wordPair.asUpperCase,
            style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),),
        );
      });
      //Now return a widget, we choose "Scaffold"
      return new Scaffold(
        appBar: new AppBar(
          title: new Text("Checked words"),
        ),
        body: new ListView(children: listTiles.toList(),),//Lazy list(Iterable) => List
      );
    });
    Navigator.of(context).push(pageRoute);
  }
  Widget _buildRow(WordPair wordPair, int index) {
    //This widget is for each row
    final textColor = index % 2 == 0 ? Colors.red : Colors.blue;
    final isChecked = _checkedWords.contains(wordPair);
    return new ListTile(
      //leading = left, trailing = right. Is is correct ? Not yet
      leading: new Icon(
        isChecked ? Icons.check_box : Icons.check_box_outline_blank,
        color: textColor,
      ),
      title: new Text(
        wordPair.asUpperCase,
        style: new TextStyle(fontSize: 18.0, color: textColor),
      ),
      onTap: () {
        setState(() {
          //This is an anonymous function
          if (isChecked) {
            _checkedWords.remove(wordPair);//Remove item in a Set
          } else {
            _checkedWords.add(wordPair);//Add item to a Set
          }
        });
      },
    );
  }
}

class MyApp extends StatelessWidget {
  //Stateless = immutable = cannot change object's properties
  //Every UI components are widgets
  @override
  Widget build(BuildContext context) {
    //build function returns a "Widget"
    return new MaterialApp(
        title: "This is my first Flutter App",
        home: new RandomEnglishWords()
    );//Widget with "Material design"
  }
}

2 个答案:

答案 0 :(得分:2)

首先,关于MaterialPageRoute的问题无济于事。这是它的官方解释:

  

MaterialPageRoute很方便,因为它可以过渡到新的   屏幕使用平台特定的动画。

您看到的那些动画是特定于平台的动画。

如果要实现自定义动画,则需要使用PageRouteBuilder手动实现。这是您的操作方法。

这是_pushToSavedWordsScreen的修改版本,它从右向左过渡。在Google Pixel上进行了测试。

final pageRoute = new PageRouteBuilder(
  pageBuilder: (BuildContext context, Animation animation,
      Animation secondaryAnimation) {
    // YOUR WIDGET CODE HERE
    final listTiles = _checkedWords.map((wordPair) {
      return new ListTile(
        title: new Text(
          wordPair.asUpperCase,
          style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
        ),
      );
    });
    //Now return a widget, we choose "Scaffold"
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Checked words"),
      ),
      body: new ListView(
        children: listTiles.toList(),
      ), //Lazy list(Iterable) => List
    );
  },
  transitionsBuilder: (BuildContext context, Animation<double> animation,
      Animation<double> secondaryAnimation, Widget child) {
    return SlideTransition(
      position: new Tween<Offset>(
        begin: const Offset(1.0, 0.0),
        end: Offset.zero,
      ).animate(animation),
      child: new SlideTransition(
        position: new Tween<Offset>(
          begin: Offset.zero,
          end: const Offset(1.0, 0.0),
        ).animate(secondaryAnimation),
        child: child,
      ),
    );
  },
);
Navigator.of(context).push(pageRoute);

答案 1 :(得分:0)

这是新导航的修改后的代码。 Android和iOS都可以水平导航。 原始代码:https://flutter.io/get-started/codelab/[1]

pubspec.yaml ...不要忘记添加:

dependencies:
  flutter:
    sdk: flutter
  english_words:  ^3.1.0 #version 3.1.0 or above

更新的代码:main.dart。

/*
Nguyen Duc Hoang(Mr)
Programming tutorial channel:
https://www.youtube.com/c/nguyenduchoang
Flutter, React, React Native, IOS development, Swift, Python, Angular
* */
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

//Define "root widget"
void main() => runApp(new MyApp());//one-line function
//StatefulWidget
class RandomEnglishWords extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new RandomEnglishWordsState();//return a state's object. Where is the state's class ?
  }
}
//State
class RandomEnglishWordsState extends State<RandomEnglishWords> {
  final _words = <WordPair>[
  ]; //Words displayed in ListView, 1 row contains 1 word
  final _checkedWords = new Set<WordPair>(); //set contains "no duplicate items"
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    //Now we replace this with a Scaffold widget which contains a ListView
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("List of English words"),
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list),
              onPressed: _pushToSavedWordsScreen)
        ],
      ),
      body: new ListView.builder(itemBuilder: (context, index) {
        //This is an anonymous function
        //index = 0, 1, 2, 3,...
        //This function return each Row = "a Widget"
        if (index >= _words.length) {
          _words.addAll(generateWordPairs().take(10));
        }
        return _buildRow(_words[index], index); //Where is _buildRow ?
      }),
    );
  }

  _pushToSavedWordsScreen() {
//    print("You pressed to the right Icon");
    //To navigate, you must have a "route"

//======================================================================
//=======  original solution  -  ANDROID transitions Vertically
//    final pageRoute = new MaterialPageRoute(builder: (context) {
//      //map function = Convert this list to another list(maybe different object's type)
//      //_checkedWords(list of WordPair) => map =>
//      // converted to a lazy list(Iterable) of ListTile
//      final listTiles = _checkedWords.map( (wordPair) {
//        return new ListTile(
//          title: new Text(wordPair.asUpperCase,
//            style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),),
//        );
//      });
//      //Now return a widget, we choose "Scaffold"
//      return new Scaffold(
//        appBar: new AppBar(
//          title: new Text("Checked words"),
//        ),
//        body: new ListView(children: listTiles.toList(),),//Lazy list(Iterable) => List
//      );
//    });
//    Navigator.of(context).push(pageRoute);
//  }
    //===========   OLD solution...  ANDROID transitions Vertically
    //==================================================================



    //==================================================================
    //===========   new solution...  transition Horizontal

    final pageRoute = new PageRouteBuilder(
      pageBuilder: (BuildContext context, Animation animation,
          Animation secondaryAnimation) {
        // YOUR WIDGET CODE HERE
        final listTiles = _checkedWords.map((wordPair) {
          return new ListTile(
            title: new Text(
              wordPair.asUpperCase,
              style: new TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
            ),
          );
        });
        //Now return a widget, we choose "Scaffold"
        return new Scaffold(
          appBar: new AppBar(
            title: new Text("Checked words"),
          ),
          body: new ListView(
            children: listTiles.toList(),
          ), //Lazy list(Iterable) => List
        );
      },
      transitionsBuilder: (BuildContext context, Animation<double> animation,
          Animation<double> secondaryAnimation, Widget child) {
        return SlideTransition(
          position: new Tween<Offset>(
            begin: const Offset(1.0, 0.0),
            end: Offset.zero,
          ).animate(animation),
          child: new SlideTransition(
            position: new Tween<Offset>(
              begin: Offset.zero,
              end: const Offset(1.0, 0.0),
            ).animate(secondaryAnimation),
            child: child,
          ),
        );
      },
    );
    Navigator.of(context).push(pageRoute);
  }
  //=========  end of solution
  //=============================================================

    Widget _buildRow(WordPair wordPair, int index) {
      //This widget is for each row
      final textColor = index % 2 == 0 ? Colors.red : Colors.blue;
      final isChecked = _checkedWords.contains(wordPair);
      return new ListTile(
        //leading = left, trailing = right. Is is correct ? Not yet
        leading: new Icon(
          isChecked ? Icons.check_box : Icons.check_box_outline_blank,
          color: textColor,
        ),
        title: new Text(
          wordPair.asUpperCase,
          style: new TextStyle(fontSize: 18.0, color: textColor),
        ),
        onTap: () {
          setState(() {
            //This is an anonymous function
            if (isChecked) {
              _checkedWords.remove(wordPair); //Remove item in a Set
            } else {
              _checkedWords.add(wordPair); //Add item to a Set
            }
          });
        },
      );
    }
  }





class MyApp extends StatelessWidget {
  //Stateless = immutable = cannot change object's properties
  //Every UI components are widgets
  @override
  Widget build(BuildContext context) {
    //build function returns a "Widget"
    return new MaterialApp(
        title: "This is my first Flutter App",
        home: new RandomEnglishWords()
    );//Widget with "Material design"
  }
}