CÔNG NGHỆ THÔNG TIN >> BÀI VIẾT CHỌN LỌC

Flutter cơ bản-Hướng dẫn tạo GestureDetector Widget với thao tác di chuyển và phóng to thu nhỏ hình ảnh

Đăng lúc: 09:16 AM - 07/06/2024 bởi Charles Chung - 253

Gestures là một tính năng trong Flutter cho phép chúng ta tương tác với ứng dụng di động qua màn hình cảm ứng, trong bài viết này tôi sẽ hướng dẫn các bạn tạo một GestureDetector Widget với thao tác di chuyển và phóng to thu nhỏ hình ảnh.

1. Yêu cầu chung

  • Có kiến thức về lập trình Dart
  • Máy đã cài đặt môi trường phát triển ứng dụng Flutter

2. Mô tả về cử chỉ trên màn hình cảm ứng

  • Khi màn hình di động bị khóa, bạn trượt ngón tay trên màn hình để mở khóa.
  • Nhấn vào một nút trên màn hình điện thoại di động của bạn và
  • Nhấn và giữ biểu tượng ứng dụng trên thiết bị dựa trên cảm ứng để kéo biểu tượng đó qua các màn hình.

Tap − Chạm vào bề mặt thiết bị bằng đầu ngón tay trong thời gian ngắn sau đỏ thả ngón tay ra ngay
Double Tap − Tap 2 lần trong thời gian ngắn
Drag − Chạm vào bề mặt của thiết bị bằng đầu ngón tay và sau đó di chuyển đầu ngón tay một cách ổn định và cuối cùng thả ngón tay ra.
Flick − Tương tự như drag nhưng thực hiện nhanh hơn.
Pinch − Chụm bề mặt của thiết bị bằng hai ngón tay
Spread/Zoom − Ngược lại với Pinch.
Panning − Chạm vào bề mặt của thiết bị bằng đầu ngón tay và di chuyển nó theo bất kỳ hướng nào mà không nhả đầu ngón tay.

3. Giới thiệu GestureDetector Widget

Flutter cung cấp một sự hỗ trợ tuyệt vời để xử lý tất cả các loại cử chỉ thông qua một tiện ích duy nhất GestureDetector.  Để xác định các cử chỉ tác động lên một widget, ta chỉ cần đặt widget đó bên trong GestureDetector widget. GestureDetector sẽ bắt các cử chỉ và gửi nhiều sự kiện dựa trên cử chỉ đó.

4. Sử dụng GestureDetector

Ví dụ sau đây sẽ thực hiện việc zoom in/out một hình ảnh sử dụng cử chỉ Scale của GestureDetector Widget

- Tạo project Flutter: các bạn có thể thực hiện theo 2 cách:

  • Mở Android Studio -> tạo project flutter với tên "GestureZoomImage"
  • Gõ lệnh tạo project tại dòng lệnh

flutter create example_validate_form

- Cấu trúc các widget trên màn hình

- Mở file main.dart code khung cơ bản theo gợi ý sau

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

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Example01-Lab12',
      home: MyBox(),
      debugShowCheckedModeBanner: false,
    );
  }
}
class MyBox extends StatefulWidget {
  @override
  State<MyBox> createState() => _MyBoxState();
}
class _MyBoxState extends State<MyBox> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Thao tác cử chỉ trên mobile'),),
      body: Stack(
        fit: StackFit.expand,
        children: [
          Container(
            padding: EdgeInsets.all(10),
            color: Colors.white60,
            child: Text('Chạm vào hình giữ và kéo hoặc zoom',style: TextStyle(fontSize: 26),),
          ),
        ],
      ),
    );
  }
}

- Tạo thư mục assets/images trong project sau đó copy hình ảnh bạn muốn vào đó -> cấu hình assets trong tệp pubspec.yaml

- Để điều khiển cử chỉ bạn cần tạo một GestureDetector widget chứa một hình ảnh bên trong và đăng ký sự kiện Scale, hãy xem đoạn code sau

Positioned(
 top: 0, //giá trị này sẽ phải cập nhật lại khi sự kiện thay đổi
 left: 0, //giá trị này sẽ phải cập nhật lại khi sự kiện thay đổi
 child: GestureDetector(
        onScaleStart: (detail){}, //sự kiện bắt đầu thay đổi
        onScaleUpdate:(detail){}, //sự kiện cập nht thay đổi
        child: SizedBox(
               width: 100, //giá trị này sẽ phải cập nhật lại khi sự kiện thay đổi
               height: 100, //giá trị này sẽ phải cập nhật lại khi sự kiện thay đổi
               child: const CircleAvatar(backgroundImage: AssetImage("assets/icon-support.png"), backgroundColor: Colors.white60,),
                       ),
           )
)

Như vậy chúng ta cần khai báo các biến lưu trữ vị trí ban đầu, và vị trí sẽ thay đổi của Positioned và tỉ lệ zoom của SizeBox, tiếp theo cần cập nhật lại các giá trị và tỉ lệ zoom trong 2 sự kiện Scale. đoạn code hoàn chỉnh của lớp _MyBoxState như sau:

class _MyBoxState extends State<MyBox> {
  //tiêu điểm bắt đầu
  late Offset _startingFocalPoint;
  //vị trí trước
  late Offset _previousOffset;
  //vị trí hiện tại
  Offset _offset = Offset.zero;
  //giá trị zoom trước
  late double _previousZoom;
  //giá trị zoom ban đầu
  double _zoom = 1.0;
  //kích thước hình ban đầu
  final containerSize = const Size(100, 100);
  //phương thức đáp ứng sự kiện bắt đầu thay đổi tỉ lệ
  void _handleScaleStart(ScaleStartDetails details) {
    setState(() {
      _startingFocalPoint = details.focalPoint;
      _previousOffset = _offset;
      _previousZoom = _zoom;
    });
  }
  //phương thức đáp ứng sự kiện cập nhật lại giá trị khi thay đổi
  void _handleScaleUpdate(ScaleUpdateDetails details) {
    setState(() {
      _zoom = _previousZoom * details.scale;
      final Offset normalizedOffset = (_startingFocalPoint - _previousOffset) / _previousZoom;
      _offset = details.focalPoint - normalizedOffset * _zoom;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Thao tác cử chỉ trên mobile'),),
      body: Stack(
        fit: StackFit.expand,
        children: [
          Container(
            padding: EdgeInsets.all(10),
            color: Colors.white60,
            child: Text('Chạm vào hình giữ và kéo hoặc zoom',style: TextStyle(fontSize: 26),),
          ),
          Positioned(
              top: _offset.dy,
              left: _offset.dx,
              child: GestureDetector(
                onScaleStart: _handleScaleStart, //sự kiện bắt đầu thay đổi
                onScaleUpdate:_handleScaleUpdate, //sự kiện cập nht thay đổi
                child: SizedBox(
                  width: containerSize.width * _zoom,
                  height: containerSize.height * _zoom,
                  child: const CircleAvatar(backgroundImage: AssetImage("assets/icon-support.png"), backgroundColor: Colors.white60,),
                ),
              )
          ),
        ],
      ),
    );
  }
}

- Chạy ứng dụng và kiểm tra kết quả

thay lời cảm ơn!

QUẢNG CÁO - TIẾP THỊ