Как ограничить изображение на холсте

Я хотел бы нарисовать на холсте изображение размером 200x200 пикселей, а затем проделать с ним кое-что еще. У меня есть изображение 900x690, поэтому в идеале я хотел бы "кадрировать по центру" изображение, чтобы использовать термин Android. Это видео почему-то советует нам использоватьFittedBox а затем SizedBox. Я также попытался поместить оба из них вContainer. Я попытался установить размер контейнера, размер коробки и художника клиентаSizeдо 200x200, и в результате получается полноэкранное изображение. Кто знает что делаю не так:)

Вот код:

import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  ui.Image image;

  @override
  void initState() {
    super.initState();
    load('images/noodlejpg.jpg').then((i) {
      setState(() {
        image = i;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(backgroundColor: Colors.blue, title: Text('I am a title')),
      backgroundColor: Colors.teal,
      body: SafeArea(
        child: FittedBox(
          child: SizedBox(
            width: 200.0,
            height: 200.0,
            child: CustomPaint(
              painter: MyPainter(image),
            ),
          ),
        ),
      ),
    );
  }

  Future<ui.Image> load(String asset) async {
    ByteData data = await rootBundle.load(asset);
    ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List());
    ui.FrameInfo fi = await codec.getNextFrame();
    return fi.image;
  }
}

class MyPainter extends CustomPainter {
  ui.Image image;

  MyPainter(this.image);

  @override
  void paint(Canvas canvas, Size size) {
    var paint = new Paint();
    paint.blendMode = BlendMode.srcIn;
    paint.isAntiAlias = true;

    if (image != null) canvas.drawImage(image, Offset.zero, paint);
  }

  @override
  bool shouldRepaint(MyPainter oldDelegate) {
    return image != oldDelegate.image;
  }
}

3 ответа

Хорошо, я нашел ответ на это. Есть встроенная функция рисования под названиемpaintImage. Не знаю, почему в видео об этом не упоминается, может, оно новое.

Итак, в самой функции рисования все, что нужно, это следующее:

  @override
  void paint(Canvas canvas, Size size) {
    paintImage(
        canvas: canvas,
        rect: Rect.fromLTRB(0, 0, 200, 200),
        image: image,
        fit: BoxFit.cover);
  }

BoxFit.coverЯ считаю, это аналог "кадрирования по центру" изображения. В исходном коде вы можете видеть, что он загружает элементы scale / source / dest rect, но ключом к этому являетсяdrawImageRect функция.

Попробуйте так

      @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(backgroundColor: Colors.blue, title: Text('I am a title')),
      backgroundColor: Colors.teal,
      body: SafeArea(
        child: Container(
          height: 200.0,
          width: 200.0,
          child: FittedBox(
            child: SizedBox(
              height: image.height.toDouble(),
              width: image.width.toDouble(),
              child: CustomPaint(
                painter: MyPainter(image),
              ),
            ),
          ),
        ),
      ),
    );
  }

Установить размер кодека изображения: http://instantiateImageCodec%20function

Future<Codec> instantiateImageCodec (
       Uint8List list,
       {int targetWidth,
       int targetHeight}
)
Другие вопросы по тегам