2024-08-07



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('Checkbox 和 CheckboxListTile 示例'),
        ),
        body: CheckboxListExample(),
      ),
    );
  }
}
 
class CheckboxListExample extends StatefulWidget {
  @override
  _CheckboxListExampleState createState() => _CheckboxListExampleState();
}
 
class _CheckboxListExampleState extends State<CheckboxListExample> {
  bool isChecked = false;
 
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Checkbox(
          value: isChecked,
          onChanged: (bool value) {
            setState(() {
              isChecked = value;
            });
          },
        ),
        Text(isChecked ? '选中' : '未选中'),
        SizedBox(height: 20),
        CheckboxListTile(
          value: isChecked,
          onChanged: (bool value) {
            setState(() {
              isChecked = value;
            });
          },
          title: Text('这是一个复选框列表标题'),
          subtitle: Text('这是一个复选框列表的副标题。'),
          secondary: Icon(Icons.drag_handle),
        ),
      ],
    );
  }
}

这段代码演示了如何在Flutter中使用CheckboxCheckboxListTileCheckbox是一个简单的复选框组件,而CheckboxListTile则是一个结合了ListTile的复选框组件,它除了可以显示文本和图标外,还可以显示副标题。代码中定义了一个状态ful组件,并在其中使用了一个布尔值来跟踪复选框的选中状态,并在复选框或列表标题被点击时更新这个状态。

2024-08-07

为了在阿里云服务器上部署Vue前端项目并通过公网IP进行访问,你需要执行以下步骤:

  1. 准备阿里云服务器:确保你有一个已购买的阿里云服务器,并且有SSH登录权限。
  2. 安装Nginx:通过SSH登录到服务器后,安装Nginx。



sudo apt update
sudo apt install nginx
  1. 配置Nginx:将Vue项目的构建输出复制到Nginx的服务目录。



# 假设你的Vue项目位于/path/to/your/vue-project
cd /path/to/your/vue-project
npm run build
sudo cp -r dist/* /var/www/html
  1. 配置Nginx服务器块:编辑Nginx配置文件。



sudo nano /etc/nginx/sites-available/default

将其中的root /var/www/html;修改为你的Vue项目构建输出目录的路径,通常是dist

  1. 重启Nginx服务:



sudo systemctl restart nginx
  1. 确保安全组规则:登录到阿里云控制台,检查你的ECS实例的安全组规则,确保80端口(HTTP)和443端口(HTTPS,如果你打算使用)对外开放。
  2. 获取公网IP:在阿里云控制台查看你的ECS实例的公网IP。
  3. 通过公网IP访问网站:使用浏览器访问你的公网IP,你的Vue前端项目现在应该可以通过公网访问了。

注意:确保你的Vue项目已经配置了正确的路由模式(hash或history),如果使用history模式,你可能需要配置Nginx重写规则以确保前端路由正常工作。

2024-08-07

在Flutter中,Dart提供了async/await来简化多线程编程。Flutter中的线程主要有两种:UI线程和computation(计算)线程。

UI线程:主要负责渲染页面和处理用户的交互事件,这是一个单线程模型,所有的UI更新都应该在这个线程中进行。

Computation(计算)线程:主要用于执行耗时任务,比如网络请求、文件操作等。

  1. 使用Isolate

Isolate是Dart中的线程,可以用来执行后台任务,避免阻塞UI线程。




import 'dart:isolate';
 
void main() {
  ReceivePort receivePort = ReceivePort();
  Isolate.spawn(isolateFunc, receivePort.sendPort);
 
  receivePort.listen((message) {
    print("Received message in main: $message");
  });
}
 
void isolateFunc(SendPort sendPort) {
  ReceivePort receivePort = ReceivePort();
  sendPort.send(receivePort.sendPort);
 
  receivePort.listen((message) {
    print("Received message in isolate: $message");
  });
}
  1. 使用async/await

async/await是Dart中处理异步操作的方式,可以让多线程编程变得简单。




Future<void> fetchData() async {
  String data = await httpGet('https://example.com/data');
  updateUI(data);
}
  1. 使用Future

Future是Dart中表示将来会发生的事情的类,可以用来处理异步操作。




Future<void> fetchData() {
  return httpGet('https://example.com/data').then((data) {
    updateUI(data);
  });
}

以上就是Flutter中的多线程编程,可以帮助开发者更好地处理耗时操作,避免阻塞UI线程,从而提高用户体验。

2024-08-07



<template>
  <div id="app">
    <quill-editor v-model="content"></quill-editor>
  </div>
</template>
 
<script>
import { quillEditor } from 'vue-quill'
 
export default {
  components: {
    quillEditor
  },
  data() {
    return {
      content: ''
    }
  }
}
</script>
 
<style>
@import '~quill/dist/quill.core.css';
@import '~quill/dist/quill.snow.css';
@import '~quill/dist/quill.bubble.css';
</style>

这段代码展示了如何在Vue应用中引入vue-quill富文本编辑器组件,并在一个简单的Vue实例中使用它。quill-editor组件绑定了一个名为content的Vue实例数据属性,用于获取和设置编辑器的内容。在<style>标签中导入了Quill的样式文件,以确保编辑器正确显示。

2024-08-07



import 'package:flutter_nfc_kit/flutter_nfc_kit.dart';
 
void main() async {
  // 初始化NFC
  FlutterNfcKit.initialize(onSessionClosed: () {
    // 当NFC会话被关闭时调用
    print("NFC session closed");
  });
 
  // 检查NFC功能是否可用
  bool isAvailable = await FlutterNfcKit.isAvailable();
  print("NFC is available: $isAvailable");
 
  // 开启NFC会话
  try {
    NFCTag tag = await FlutterNfcKit.startSession(
      onTagDiscovered: (NFCTag discoveredTag) async {
        // 当发现NFC标签时调用
        print("Discovered tag: ${discoveredTag.type}");
        // 处理标签...
      },
      onNdefDiscovered: (NDEFMessage message, NFCTag tag) async {
        // 当发现NDEF消息时调用
        print("Discovered NDEF message");
        // 处理NDEF消息...
      },
    );
    print("Session started with tag: ${tag.type}");
  } catch (e) {
    // 处理错误...
    print("Error starting NFC session: $e");
  }
}

这段代码展示了如何在Flutter中使用flutter\_nfc\_kit插件来初始化NFC、检查NFC功能是否可用,以及如何开启NFC会话并监听标签的发现。代码中包含了错误处理和标签类型的识别,这对于开发跨平台NFC应用程序是非常有用的。

2024-08-07

在Flutter中,Dismissible控件用于创建可以通过滑动来删除或进行其他操作的列表项。以下是一个简单的使用示例:




import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: DismissibleItemList(),
        ),
      ),
    );
  }
}
 
class DismissibleItemList extends StatefulWidget {
  @override
  _DismissibleItemListState createState() => _DismissibleItemListState();
}
 
class _DismissibleItemListState extends State<DismissibleItemList> {
  final List<String> items = List.generate(20, (i) => 'Item ${i + 1}');
 
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: items.length,
      itemBuilder: (context, index) {
        return Dismissible(
          key: Key(items[index]),
          onDismissed: (direction) {
            setState(() {
              items.removeAt(index);
            });
          },
          child: ListTile(title: Text('${items[index]}')),
          background: Container(color: Colors.red),
        );
      },
    );
  }
}

在这个例子中,我们创建了一个可以滑动删除列表项的DismissibleItemList控件。每个ListTile都被Dismissible包裹,允许用户通过滑动来删除。当列表项被删除时,onDismissed回调会被调用,并且通过setState更新UI,从列表中移除已经删除的项。

2024-08-07

在Flutter开发中,输入框(TextField)是一个常用的组件。然而,开发者经常会遇到与输入法(例如软键盘)交互时出现的各种问题。以下是一些常见的与输入法相关的bug以及解决方法:

  1. 输入法遮挡内容

    • 解决方法:使用StackMediaQuery来确保TextField在软键盘弹出时能够正确显示。
  2. 输入法弹出时导致布局跳转

    • 解决方法:使用SingleChildScrollViewListView来确保布局在软键盘弹出时保持不变。
  3. 输入法弹出时内容无法滚动到视图中

    • 解决方法:使用Scrollable小部件(如ListViewSingleChildScrollView)包裹TextField,并确保在软键盘弹出时可以滚动到TextField
  4. 输入法弹出时内容被遮挡

    • 解决方法:使用ScaffoldresizeToAvoidBottomInset属性,该属性会在软键盘弹出时自动调整顶部内容的padding以避免被遮挡。
  5. 输入法弹出时导致无法获取焦点

    • 解决方法:确保TextField在软键盘弹出后能够自动获取焦点。可以在TextFieldfocusNode属性中设置autofocustrue
  6. 软键盘弹出时导致布局错乱

    • 解决方法:使用LayoutBuilder来监听布局变化,并在软键盘弹出时调整布局。
  7. 软键盘不弹出或弹出异常

    • 解决方法:确保TextField是在可交互的窗口小部件中。如果是Web,确保在浏览器环境中运行。
  8. 软键盘与输入法切换导致的布局问题

    • 解决方法:监听输入法变化事件,并在事件发生时调整布局。

每个问题的具体解决方法可能会根据实际情况有所不同,但以上提供的策略可以作为处理这些问题的起点。

2024-08-07

在Flutter中,如果你在Text组件中看到了黄色的双下划线,这通常表示文本被识别为可点击的或可选中的,比如链接或可编辑的文本。

解决这个问题的方法取决于你的具体需求:

  1. 如果你不希望文本被点击或选中,可以将Text组件的selectable属性设置为false,并将onSelectionChanged属性设置为null。例如:



Text(
  '你的文本内容',
  selectable: false,
  onSelectionChanged: null,
),
  1. 如果你需要文本是可点击的或可选中的,那么这个下划线是正常的行为。你可以通过style属性来自定义这些下划线的样式,例如将颜色改为其他颜色或去除下划线:



Text.rich(
  TextSpan(
    text: '你的文本内容',
    style: TextStyle(
      decoration: TextDecoration.none, // 去除下划线
    ),
  ),
  selectable: true,
  // 如果需要处理点击事件,可以在这里设置 onTap 等回调
),
  1. 如果你使用的是Material组件库,可能是因为文本被包裹在SelectableText组件中,这时可以通过设置cursorRadiuscursorColor来自定义光标的样式,从而间接影响到下划线的显示:



SelectableText(
  '你的文本内容',
  cursorColor: Colors.transparent, // 透明光标颜色
  cursorRadius: Radius.circular(1), // 圆形光标半径
),

请根据你的具体需求选择合适的方法来解决问题。

2024-08-07

在Flutter中,List组件通常指的是ListView,它是一个可滚动的列表组件,可以垂直或水平滚动显示其内容。

以下是一些基本的ListView使用示例:

  1. 垂直ListView:



ListView(
  children: <Widget>[
    ListTile(
      title: Text('Item 1'),
    ),
    ListTile(
      title: Text('Item 2'),
    ),
    ListTile(
      title: Text('Item 3'),
    ),
    // ... 更多的ListTile
  ],
)
  1. 水平ListView:



ListView(
  scrollDirection: Axis.horizontal,
  children: <Widget>[
    Container(width: 160.0, color: Colors.red),
    Container(width: 160.0, color: Colors.blue),
    Container(width: 160.0, color: Colors.green),
    // ... 更多的子Widget
  ],
)
  1. 使用ListView.builder来创建大量列表项:



ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) {
    return ListTile(title: Text('Item $index'));
  },
)
  1. 列表加载网络数据(使用ListView.builder和FutureBuilder):



ListView.builder(
  itemCount: data.length,
  itemBuilder: (context, index) {
    return FutureBuilder(
      future: someAsyncCall(data[index]),
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return ListTile(title: Text(snapshot.data));
        } else {
          return ListTile(title: CircularProgressIndicator());
        }
      },
    );
  },
)

这些示例展示了如何在Flutter中创建和使用ListView,包括垂直和水平方向的滚动列表,以及如何使用ListView.builder来高效地创建大量列表项。

2024-08-07

在这个系列的文章中,我们已经讨论了Java、Kotlin、React Native (RN)和Flutter这四种开发技术,以及它们产生的App大小。这是第二部分,包含了Flutter的App大小。

Flutter是一个由Google开发的开源移动应用开发框架,它可以让开发者使用同一套代码库构建高性能、高质量的iOS和Android应用。Flutter使用Dart作为编程语言,并提供了丰富的widget库来帮助开发者快速构建界面。

对于Flutter App的大小,我们可以通过实际的项目来进行分析。假设我们有一个空的Flutter项目,并且只包含了必要的Widget,那么App的大小可以用以下方法来估计:

  1. 使用flutter build apkflutter build ios命令来构建APK或IPA文件。
  2. 使用工具如zipalign(仅适用于Android)或者解压缩工具来查看APK或IPA文件的大小。

以下是一个基于Flutter的空应用的大致大小估计:

  • APK(Android)大约为10MB左右。
  • IPA(iOS)大约为10MB左右。

请注意,这些大小是基于一个空应用的估计,实际应用可能会根据其内容和依赖项的大小而有所不同。

由于Flutter使用Dart作为编程语言,因此它的App大小并不会像Java或Kotlin编写的App那样大,因为它不包含Java虚拟机或Android Framework的额外二进制文件。Flutter使用Dart VM和原生平台的服务来提供更小的App体积和更快的启动时间。

总结:Flutter开发的App通常比其他技术开发的App小,这是因为它使用Dart作为编程语言,并且不包含Java虚拟机或其他额外的二进制文件。