2024-08-19

Flutter 的 UI 框架基于组件(widget)的概念,其中每个组件都是一个 StatelessWidget 或者 StatefulWidget

StatelessWidget 是不可变的,不会改变状态。这意味着它的 build 方法总是返回相同的结果。

StatefulWidget 可以在其生命周期内改变状态,这通过一个 State 对象来管理。每当 State 对象的 setState 方法被调用时,Flutter 就知道状态已经改变,并且需要重新构建 UI。

以下是一个简单的计数器示例,展示了如何创建一个 StatefulWidget 并在用户点击按钮时更新 UI。




import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterPage(),
    );
  }
}
 
class CounterPage extends StatefulWidget {
  @override
  _CounterPageState createState() => _CounterPageState();
}
 
class _CounterPageState extends State<CounterPage> {
  int _counter = 0;
 
  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter App'),
      ),
      body: Center(
        child: Text(
          '$_counter',
          style: Theme.of(context).textTheme.headline4,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

在这个例子中,CounterPage 是一个 StatefulWidget,它有一个关联的 _CounterPageState 类,它管理着计数器的状态。当用户点击浮动动作按钮时,_incrementCounter 方法被调用,这导致计数器的值增加,并通过 setState 方法触发 UI 重新构建。这个过程是 Flutter 中 UI 框架的核心原理之一。

2024-08-19



import 'package:flutter/services.dart';
import 'package:umeng_common_sdk/umeng_common_sdk.dart';
 
void main() {
  runApp(MyApp());
 
  // 初始化友盟统计SDK
  UmengCommonSdk.init('YOUR_APP_KEY'); // 替换为你的APP_KEY
}
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 配置Android和iOS的通道
    const MethodChannel('umeng_common_sdk').setMethodCallHandler((call) {
      if (call.method == 'onPageStart') {
        UmengCommonSdk.onPageStart(call.arguments);
      } else if (call.method == 'onPageEnd') {
        UmengCommonSdk.onPageEnd(call.arguments);
      }
    });
 
    return MaterialApp(
      home: HomePage(),
    );
  }
}
 
class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 你的页面内容
    );
  }
}

在这个代码实例中,我们首先导入了必要的Flutter和友盟统计SDK。在main函数中,我们初始化了友盟统计SDK,并运行了我们的应用。在MyApp类中,我们配置了方法通道以处理页面视图统计。HomePage类是应用的主页面。这个例子展示了如何在Flutter中集成友盟统计SDK,并进行基本的页面统计。

2024-08-19

Flutter 中的设计系统主要指的是其Material和Cupertino两种视觉风格的组件。Material Design 是一种设计语言,而Cupertino则是模仿iOS的设计风格。

以下是如何在Flutter中使用这两种设计风格的简单示例:

Material Design 示例:




import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Material Design Example'),
        ),
        body: Center(
          child: MaterialButton(
            child: Text('Press Me'),
            onPressed: () => print('Button Pressed'),
          ),
        ),
      ),
    );
  }
}

Cupertino 示例:




import 'package:flutter/cupertino.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      home: CupertinoPageScaffold(
        navigationBar: CupertinoNavigationBar(
          middle: Text('Cupertino Example'),
        ),
        child: Center(
          child: CupertinoButton(
            child: Text('Press Me'),
            onPressed: () => print('Button Pressed'),
          ),
        ),
      ),
    );
  }
}

在这两个示例中,我们创建了一个简单的应用,使用了Flutter提供的Material和Cupertino组件。MaterialApp和CupertinoApp分别定义了应用的顶级属性,如主题色和标题。Scaffold和CupertinoPageScaffold提供了顶部栏、底部栏和主内容区的基本结构。MaterialButton和CupertinoButton是可点击的按钮组件。

2024-08-19



import 'package:flutter/material.dart';
import 'package:flutter_gallery_ultimate/utils/Data.dart';
import 'package:flutter_gallery_ultimate/utils/Utils.dart';
 
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
 
  final String title;
 
  @override
  _MyHomePageState createState() => _MyHomePageState();
}
 
class _MyHomePageState extends State<MyHomePage> {
  int currentPage = 0;
  List<String> images = Data.imageList;
 
  void _loadMore() {
    setState(() {
      currentPage++;
      images.addAll(Data.imageList);
    });
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: ListView.builder(
        itemCount: images.length,
        itemBuilder: (context, index) {
          return Utils.imageItem(images[index], context);
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _loadMore,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ), 
    );
  }
}

在这个代码实例中,我们创建了一个名为MyHomePage的StatefulWidget,它维护了当前页面的状态。在_MyHomePageState状态类中,我们定义了一个_loadMore函数来加载更多图片,并通过ListView.builder构建了一个可以无限滚动的图片列表。每次用户点击浮动动作按钮时,就会调用_loadMore函数,从而加载更多的图片。这个例子展示了如何在Flutter中实现图片列表的分页加载。

2024-08-19

SliverAppBar 是 Flutter 中用于创建可滚动的应用栏,它通常在 CustomScrollView 中使用,并且可以包含一个导航栏、标题、操作按钮、TabBar、以及一个用于展示内容的 flexibleSpace。

以下是一个简单的 SliverAppBar 使用示例:




CustomScrollView(
  slivers: <Widget>[
    SliverAppBar(
      pinned: true,
      expandedHeight: 200.0,
      flexibleSpace: const FlexibleSpaceBar(
        title: Text('SliverAppBar Example'),
      ),
      actions: <Widget>[
        IconButton(
          icon: const Icon(Icons.settings),
          onPressed: () {},
        ),
      ],
    ),
    // 其他 Sliver 小部件...
  ],
)

在这个例子中,SliverAppBar 被设置为 pinned,这意味着在滚动时它会保持在顶部。expandedHeight 属性设置了 SliverAppBar 的扩展高度。flexibleSpace 属性允许我们设置一个在 SliverAppBar 扩展时显示的布局。actions 属性用于添加一个操作按钮列表到应用栏的右侧。

2024-08-19



import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AnimatedSwitcherHome(),
    );
  }
}
 
class AnimatedSwitcherHome extends StatefulWidget {
  @override
  _AnimatedSwitcherHomeState createState() => _AnimatedSwitcherHomeState();
}
 
class _AnimatedSwitcherHomeState extends State<AnimatedSwitcherHome> {
  int _count = 0;
 
  void _incrementCounter() {
    setState(() {
      _count++;
    });
  }
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: AnimatedSwitcher(
          duration: const Duration(milliseconds: 300),
          child: Text(
            '$_count',
            key: ValueKey<int>(_count),
            style: Theme.of(context).textTheme.display1,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

这段代码演示了如何使用AnimatedSwitcher组件在点击按钮时平滑地切换显示的数字。每次点击按钮,计数器增加,并使用AnimatedSwitcher组件平滑过渡到新的数字。

2024-08-19

Flutter是一个开源的UI工具包,它可以快速在iOS和Android上构建高质量的原生用户界面。Flutter可以与现有的代码一起工作。它也可以通过自下而上的重新设计来对UI进行编程,而不是依赖于特定的设备功能。

Flutter框架的主要特点包括:

  1. 使用Dart作为编程语言。
  2. 提供Material Design和Cupertino(iOS风格)小部件。
  3. 使用Dart语言的JIT或AOT编译模式进行快速的开发周期。
  4. 提供现代的响应式框架。
  5. 支持iOS和Android以及其他移动操作系统。

以下是一个简单的Flutter应用程序的代码示例,它创建了一个按钮,当点击时在控制台输出一条消息:




import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Demo'),
        ),
        body: Center(
          child: RaisedButton(
            onPressed: () {
              print('Button was pressed.');
            },
            child: Text('Press Me'),
          ),
        ),
      ),
    );
  }
}

在这个例子中,我们首先导入了material.dart,这是Flutter框架中提供的一个库,它包含创建现代应用程序所需的所有小部件。然后我们定义了一个MyApp类,它扩展了StatelessWidget并覆盖了build方法。在build方法中,我们返回一个MaterialApp,它是一个小部件,表示整个应用程序。在应用程序中,我们设置了一个Scaffold,它提供了一个AppBar、一个body和一个FloatingActionButtonbody属性包含一个RaisedButton,当按钮被按下时,会在控制台打印一条消息。

2024-08-19

在Flutter开发中,以下是一些提高效率的方法和工具:

  1. 使用有效的布局:Flutter提供了一系列的布局小部件,如Row、Column、ListView、GridView等,可以帮助开发者高效地构建UI。
  2. 使用状态管理:Flutter提供了如Provider、Redux、BLoC等状态管理解决方案,有助于管理复杂应用的状态。
  3. 使用路由预先定义:使用MaterialApp或CupertinoApp时,可以预定义路由表,可以方便地导航到不同的页面。
  4. 使用代码生成工具:例如json_serializablefreezed等,可以帮助快速生成模型代码。
  5. 使用快捷键和命令:如Ctrl+S保存时自动运行格式化和单元测试,Ctrl+M快速切换窗口等。
  6. 使用DevTools:Flutter提供了一系列的开发工具,如DevTools,可以用于调试、性能分析等。
  7. 使用可视化布局工具:如Layout Explorer,可以帮助设计师和开发者可视化布局过程。
  8. 使用Flutter Favorite Packages站点:这个网站可以帮助开发者发现和了解Flutter的最佳实践和包。
  9. 使用Flutter Hot Reload:这是一个非常有效的开发特性,可以在不重新编译和启动应用的情况下应用代码更改和界面更新。
  10. 使用Flutter Web:虽然Flutter主要是为Android和iOS设计的,但Flutter Web提供了在网页上运行Flutter代码的可能性。

这些方法和工具可以帮助开发者提高在Flutter应用开发中的效率。

2024-08-19

在uniapp中引入iconfont字体图标库,你需要进行以下步骤:

  1. 在iconfont官网上选择所需图标,加入至项目,生成字体文件。
  2. 下载生成的字体文件到本地。
  3. 将字体文件放入uniapp项目的静态资源目录,如static/fonts/
  4. App.vue或者需要使用图标的页面的<style>标签中引入字体文件,并使用@font-face规则。
  5. 使用图标时,通过类名或者:class来应用图标字体。

示例代码:




/* App.vue 或 对应页面的 <style> 标签 */
@font-face {
  font-family: 'iconfont';
  src: url('~@/static/fonts/iconfont.eot'); /* IE9 */
  src: url('~@/static/fonts/iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
  url('~@/static/fonts/iconfont.woff') format('woff'), /* 现代浏览器 */
  url('~@/static/fonts/iconfont.ttf') format('truetype'), /* Safari, Android, iOS */
  url('~@/static/fonts/iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
}
 
.iconfont {
  font-family: "iconfont" !important;
  font-size: 16px;
  font-style: normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}



<!-- 使用图标 -->
<text class="iconfont">&#xe600;</text>

注意:

  • 使用~@/是为了确保webpack能正确解析路径。
  • 图标字符对应的是你在iconfont上选择的图标编码,这个编码可以在图标资源页面的代码段中找到。
  • 字体文件格式.eot, .woff, .ttf, .svg均需要引入,以确保不同浏览器的兼容性。
2024-08-19

在uniapp中,你可以使用uni.request方法将base64格式的图片上传到服务器。以下是一个简单的示例代码:




// 假设base64Data是你的base64格式的图片数据
const base64Data = 'data:image/png;base64,...'; // 这里应该是你的base64字符串
 
// 将base64字符串转换为二进制数据
function base64ToBlob(base64Data) {
    let arr = base64Data.split(','), mime = arr[0].match(/:(.*?);/)[1];
    let bstr = atob(arr[1]);
    let n = bstr.length;
    let u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
}
 
// 创建FormData对象
let formData = new FormData();
// 将二进制数据添加到FormData中
formData.append('file', base64ToBlob(base64Data), 'image.png'); // 'image.png'是上传后的文件名
 
// 发送请求
uni.uploadFile({
    url: '你的服务器地址', // 服务器接收上传文件的URL
    files: [{
        name: 'file', // 这里的name要和formData.append()中的name一致
        filePath: formData
    }],
    success: (uploadFileRes) => {
        console.log(uploadFileRes.data); // 输出服务器返回的数据
    },
    fail: (error) => {
        console.error(error);
    }
});

确保你的服务器能够处理multipart/form-data类型的POST请求,并且接收上传的文件。这段代码将会把base64编码的图片转换为二进制数据,然后通过uni.uploadFile方法上传到服务器。