面向React Native开发者的Flutter——调试、动画以及等价的组件对比

331 阅读7分钟

一、特定于平台的代码

在构建跨平台应用程序时,您希望跨平台充用尽可能的代码。但是还,可能会出现代码因操作系统不同而不同的情况。这需要通过声明平台来单独实现。

在React Native中,将使用以下实现:

// React Native
if (Platform.OS === 'ios') {
    return 'iOS';
} else if (Platform.OS === 'android') {
    return 'android';
} else {
    return 'not recognised';
}

在Flutter中,使用以下实现:

final platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS) {
  return 'iOS';
}
if (platform == TargetPlatform.android) {
  return 'android';
}
if (platform == TargetPlatform.fuchsia) {
  return 'fuchsia';
}
return 'not recognized';

二、调试

2.1、我可以使用哪些工具在Flutter中调试我的应用程序?

使用DevTools套件调试 Flutter 或 Dart 应用程序。

DevTools包括对分析、检查堆、检查小部件树、日志记录诊断、调试、观察执行的代行、调试内存泄口和内存碎片支持。用眼更多信息,请参阅 DevTools文档。

如果您使用的是 IDE,则可以使用 IDE 的调试器调试您的应用程序。

2.2、如何执行热重载?

Flutter的Stateful Hot Reload功能可帮助您快速轻松进行实验、构建UI、添加功能和修复错误。无需在每次进行更改时都重新编译您的应用程序,您可以立即热重新加载您的应用程序。该应用程序会更新以反映您的更改,并保留该应用程序的当前状态。

在React Native中,iOS模拟器的快捷键是⌘R,在Android模拟器上点击R两次。

在Flutter中,如果你使用的是IntelliJ IDE或Android Studio,你可以选择Save All (⌘s/ctrl-s),或者你可以点击工具栏上的Hot Reload按钮。如果你谁用flutter run在命令行运行应用程序,请在终端窗口中输入r。您还可以通过在终端窗口中输入R来执行完全重启。

2.3、如何访问应用内的开发者菜单?

在React Native中,可以通过快捷键来访问您的设备开发者菜单:⌘D 用于 iOS 模拟器或 ⌘M 用于 Android 模拟器。

在Flutter中,如果您使用的是IDE,则可以使用IDE工具。如果您使用flutter run启动您的应用程序,您还可以通过在终端窗口输入h或输入以下快捷键方式来访问菜单:

行动终端快捷方式调试函数和属性
应用程序的小部件层次结构wdebugDumpApp()
应用程序的渲染树tdebugDumpRenderTree()
图层LdebugDumpLayerTree()
辅助功能S(遍历顺序)或 U(逆命中测试顺序)debugDumpSemantics()
切换小部件检查器i小部件应用程序。showWidgetInspectorOverride
切换构造线的显示pdebugPaintSizeEnabled
模拟不同的操作系统o默认目标平台
显示性能叠加P小部件应用程序。显示性能叠加层
将屏幕截图保存到 flutter 中。PNGs 
退出q 

三、动画

精心设计的动画使UI感觉直观,有助于完善应用程序的外观和感觉,并改善用户体验。Flutter的动画支持可以轻松实现简单和复杂的动画。Flutter SDK包含许多标准运动效果的Material Design小部件,您可以轻松自定义这些效果以个性化您的应用程序。

在React Native中,Animated API用于创建动画。

在Flutter中,使用Animation类和AnimationController类。Animation是一个抽象类,它了解其当前值及其状态(已完成或已删除)。该类AnimationController允许您向前或向后播放动画,或听智慧动画并将动画设置为特定值以自定义动作。

3.1、如何添加简单的淡入动画?

在下面的Reactive Native示例中,动画组件FadeInView是使用Animated API创建的。定义了初始不透明状态、最终状态和过渡发生的持续时间。在Animated组件内部添加动画组件,将不透明度状态fadeAnim映射到我们要设置动画的Text组件的不透明度,然后调用start()调用以启动动画。

// React Native
class FadeInView extends React.Component {
    state = {
        fadeAnim: new Animated.value(0) // Initial value for opacity: 0
    };
    componentDidMount() {
        Animated.timing(this.state.fadeAnim, {
            toValue: 1,
            duration: 10000,
        }).start();
    }
    render() {
        return (
            <Animated.View style={{...this.props.style, opacity: this.state.fadeAnim }} >
                {this.props.children}
            </Animated.View>
        );
    }
}
    ...
<FadeInView>
    <Text> Fading in </Text>
<FadeInView>
    ...

要在Flutter中创建想通过的动画,请创建一个名为controllerAnimationController的对象并指定持续是时间。默认情况下AnimationController在给定的持续时间内线性生成范围从0.0到1.0的值。每当运行您的应用程序的设备准备好显示新帧时,动画控制器就会生成一个新值。通常,此速率约为每秒60个值。

在定义AnimationController时,必须传入一个vsync对象。vsync的存在可以防止屏幕外动画消耗不必要的资源。您可以通过将TickerProviderStateMixin添加到类定义来将有状态对象用作vsync.AnimationController需要一个TickerProvider,它是使用构造函数上的vsync参数配置的。

Tween描述开始值和结束值之间的插值或从输入范围到输入范围的映射。要将Tween对象与动画一起使用,请调用Tween对象的animate()方法并将它传递给要修改的Animation对象。

对于此示例,使用了FadeTransitioon小部件并将不透明度属性映射到动画对象。

要启动动画,请使用controller.forward()。其他操作也可以使用控制器执行,例如fling()repeat().对于此事例,FlutterLogo小部件用于FadeTransition小部件内。

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const Center(child: LogoFade(),));
}

class LogoFade extends StatefulWidget {
  const LogoFade({Key? key}) : super(key: key);

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

class _LogoFadeState extends State<LogoFade> with SingleTickerProviderStateMixin{
  late Animation<double> animation;
  late AnimationController controller;
  
  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      duration: const Duration(milliseconds: 3000),
      vsync: this,
    );
    final CurvedAnimation curve = CurvedAnimation(
      parent: controller,
      curve: Curves.easeIn,
    );
    animation = Tween(
      begin: 0.0,
      end: 1.0,
    ).animate(curve);
    controller.forward();
  }
  
  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: animation,
      child: const SizedBox(
        height: 300.0,
        width: 300.0,
        child: FlutterLogo(),
      ),
    );
  }
}
  • Android

flutter-fade.gif

  • iOS

flutter-fade (1).gif

3.2、如何为卡片添加滑动动画?

在React Native中,PanResponder或第三方库用于滑动动画。

在Flutter中,要添加滑动动画,请使用Dismissible小部件并嵌套小部件。

return Dismissible(
  key: Key(widget.key.toString()),
  onDismissed: (dismissDirection) {
    cards.removeLast();
  },
  child: Container(
    // ...
  ),
);
  • Android

card-swipe.gif -iOS

card-swipe (1).gif

四、React Native和Flutter widget等效组件

下表列出了常用的React Native组件映射到相应的Flutter widget和常用的widgget属性。

React Native ComponentFlutter WidgetDescription
ButtonElevatedButtonA basic raised button.
 onPressed [required]The callback when the button is tapped or otherwise activated.
 ChildThe button’s label.
   
ButtonTextButtonA basic flat button.
 onPressed [required]The callback when the button is tapped or otherwise activated.
 ChildThe button’s label.
   
ScrollViewListViewA scrollable list of widgets arranged linearly.
 children( [ ]) List of child widgets to display.
 controllerScrollController ] An object that can be used to control a scrollable widget.
 itemExtent[ double ] If non-null, forces the children to have the given extent in the scroll direction.
 scroll DirectionAxis ] The axis along which the scroll view scrolls.
   
FlatListListView.builderThe constructor for a linear array of widgets that are created on demand.
 itemBuilder [required][IndexedWidgetBuilder] helps in building the children on demand. This callback is called only with indices greater than or equal to zero and less than the itemCount.
 itemCount[ int ] improves the ability of the ListView to estimate the maximum scroll extent.
   
ImageImageA widget that displays an image.
 image [required]The image to display.
 Image. assetSeveral constructors are provided for the various ways that an image can be specified.
 width, height, color, alignmentThe style and layout for the image.
 fitInscribing the image into the space allocated during layout.
   
ModalModalRouteA route that blocks interaction with previous routes.
 animationThe animation that drives the route’s transition and the previous route’s forward transition.
   
ActivityIndicatorCircularProgressIndicatorA widget that shows progress along a circle.
 strokeWidthThe width of the line used to draw the circle.
 backgroundColorThe progress indicator’s background color. The current theme’s ThemeData.backgroundColor by default.
   
ActivityIndicatorLinearProgressIndicatorA widget that shows progress along a line.
 valueThe value of this progress indicator.
   
RefreshControlRefreshIndicatorA widget that supports the Material “swipe to refresh” idiom.
 colorThe progress indicator’s foreground color.
 onRefreshA function that’s called when a user drags the refresh indicator far enough to demonstrate that they want the app to refresh.
   
ViewContainerA widget that surrounds a child widget.
   
ViewColumnA widget that displays its children in a vertical array.
   
ViewRowA widget that displays its children in a horizontal array.
   
ViewCenterA widget that centers its child within itself.
   
ViewPaddingA widget that insets its child by the given padding.
 padding [required][ EdgeInsets ] The amount of space to inset the child.
   
TouchableOpacityGestureDetectorA widget that detects gestures.
 onTapA callback when a tap occurs.
 onDoubleTapA callback when a tap occurs at the same location twice in quick succession.
   
TextInputTextInputThe interface to the system’s text input control.
 controllerTextEditingController ] used to access and modify text.
   
TextTextThe Text widget that displays a string of text with a single style.
 data[ String ] The text to display.
 textDirectionTextAlign ] The direction in which the text flows.
   
SwitchSwitchA material design switch.
 value [required][ boolean ] Whether this switch is on or off.
 onChanged [required][ callback ] Called when the user toggles the switch on or off.
   
SliderSliderUsed to select from a range of values.
 value [required][ double ] The current value of the slider.
 onChanged [required]Called when the user selects a new value for the slider.