PageController中的nextPage()和previousPage()方法有时不起作用

时间:2017-12-20 03:13:06

标签: dart keyevent flutter television

这是我的代码: 我在Android MainActivity中响应键事件,并使用BasicMessageChannel发布关键消息:

public class MainActivity extends FlutterActivity {

private static final String CHANNEL = "scroll";
private static final String KEY_LEFT = "keyLeft";
private static final String KEY_RIGHT = "keyRight";
private BasicMessageChannel messageChannel;
private FlutterView flutterView;

private String[] getArgsFromIntent(Intent intent) {
    // Before adding more entries to this list, consider that arbitrary
    // Android applications can generate intents with extra data and that
    // there are many security-sensitive args in the binary.
    ArrayList<String> args = new ArrayList<String>();
    if (intent.getBooleanExtra("trace-startup", false)) {
        args.add("--trace-startup");
    }
    if (intent.getBooleanExtra("start-paused", false)) {
        args.add("--start-paused");
    }
    if (intent.getBooleanExtra("enable-dart-profiling", false)) {
        args.add("--enable-dart-profiling");
    }
    if (!args.isEmpty()) {
        String[] argsArray = new String[args.size()];
        return args.toArray(argsArray);
    }
    return null;
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    GeneratedPluginRegistrant.registerWith(this);
    flutterView = new FlutterView(this);
    String[] args = getArgsFromIntent(getIntent());
    FlutterMain.ensureInitializationComplete(getApplicationContext(), args);
    flutterView.runFromBundle(FlutterMain.findAppBundlePath(getApplicationContext()), null);
    messageChannel = new BasicMessageChannel<>(flutterView, CHANNEL, StringCodec.INSTANCE);
}

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getAction() == KeyEvent.ACTION_DOWN) {
        Log.d(TAG, "dispatchKeyEvent: ACTION_DOWN keyCode = " + event.getKeyCode());
        switch (event.getKeyCode()) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
                messageChannel.send(KEY_LEFT);
                return true;

            case KeyEvent.KEYCODE_DPAD_RIGHT:
                messageChannel.send(KEY_RIGHT);
                return true;

            default:
                break;
        }
    }
    return super.dispatchKeyEvent(event);
}

@Override
protected void onDestroy() {
    if (flutterView != null) {
        flutterView.destroy();
    }
    super.onDestroy();
}

@Override
protected void onPause() {
    super.onPause();
    flutterView.onPause();
}

@Override
protected void onPostResume() {
    super.onPostResume();
    flutterView.onPostResume();
}

}

当Flutter收到消息时,我调用nextPage()和previousPage()来滚动PageView,它不起作用。但我发现如果我在GestureDetector的onTap()方法中调用nextPage()和previousPage(),它可以工作:

class _Page {
  _Page({
    this.imagePath,
  });

  final String imagePath;
}

final List<_Page> _allPages = <_Page>[
  new _Page(imagePath: 'images/1.jpg'),
  new _Page(imagePath: 'images/2.jpg'),
  new _Page(imagePath: 'images/3.jpg'),
  new _Page(imagePath: 'images/4.jpg'),
  new _Page(imagePath: 'images/5.jpg'),
  new _Page(imagePath: 'images/6.jpg'),
];

class ScrollablePageDemo extends StatefulWidget {
  @override
  _ScrollablePageDemoState createState() => new _ScrollablePageDemoState();
}

class _ScrollablePageDemoState extends State<ScrollablePageDemo>
    with SingleTickerProviderStateMixin {
  PageController _controller;
  static const String _channel = 'scroll';
  static const String _emptyMessage = '';
  static const String KEY_LEFT = "keyLeft";
  static const String KEY_RIGHT = "keyRight";
  static const BasicMessageChannel<String> platform =
      const BasicMessageChannel<String>(_channel, const StringCodec());

  @override
  void initState() {
    super.initState();
    _controller = new PageController(
        initialPage: 0, keepPage: true, viewportFraction: 1.0);
    platform.setMessageHandler(changePage);
  }

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

  Future<String> changePage(String message) async {
    setState(() {
      print(message);
      if (message == KEY_RIGHT) {
        //here doesn't work
        _controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
        print("tab right: page = " + _controller.page.toString());
      } else if (message == KEY_LEFT) {
        //here doesn't work
        _controller.previousPage(duration: kTabScrollDuration, curve: Curves.ease);
        print("tab left: page = " + _controller.page.toString());
      }
    });
    return _emptyMessage;
  }

  PageView buildPageView() {
    return new PageView(
      controller: _controller,
      children: _allPages.map((_Page page) {
        return new Container(
            key: new ObjectKey(page.imagePath),
            padding: const EdgeInsets.all(12.0),
            child: new Card(
                child: new Image.asset(page.imagePath, fit: BoxFit.fill)));
      }).toList(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
        onTap: () {
          print('Listen PageView');
          //here works
          _controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
        },
        child: new Scaffold(
            appBar: new AppBar(
              title: new Text('PageView'),
            ),
            body: buildPageView()));
  }
}

void main() {
  runApp(new MaterialApp(
    title: 'Flutter Study',
    home: new ScrollablePageDemo(),
  ));
}

1 个答案:

答案 0 :(得分:0)

问题在于setState内的changePage方法。只要状态设置,setState就会调用build方法。因此,只要调用setState,页面就会再次构建。您只需从setState方法中删除changePage

示例:

Future<String> changePage(String message) async {
  print(message);
  if (message == KEY_RIGHT) {
    _controller.nextPage(duration: kTabScrollDuration, curve: Curves.ease);
    print("tab right: page = " + _controller.page.toString());
  } else if (message == KEY_LEFT) {
    _controller.previousPage(duration: kTabScrollDuration, curve: Curves.ease);
    print("tab left: page = " + _controller.page.toString());
  }
  return _emptyMessage;
}

希望有所帮助!