Pembangunan Aplikasi Mudah Alih Flutter · Pelajaran

Pemotongan, Mod Campuran dan Penggubahan Lapisan

Gunakan laluan pemotongan dan mod campuran untuk menggubah kesan visual berlapis yang canggih.

Pelajaran 3 daripada 413 langkah

Pemotongan, Mod Campuran dan Penggubahan Lapisan ialah pelajaran Pembangunan Aplikasi Mudah Alih Flutter percuma di CoddyKit. Ini ialah pelajaran 3 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Pembangunan Aplikasi Mudah Alih Flutter, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Pembangunan Aplikasi Mudah Alih Flutter merangkumi sejumlah 4 pelajaran.

Mengapa Penggubahan Lapisan Penting

Visual lanjutan dalam Flutter jarang terhasil daripada satu bentuk sahaja. Lingkaran cahaya, tindanan berkabus, imej kecil bertopeng dan lencana "potongan" dibina dengan melapiskan beberapa lukisan serta mengawal cara setiap lapisan baharu digabungkan dengan kandungan yang sedia ada pada kanvas.

Tiga alat menggerakkan proses ini pada Canvas:

  • Pemotongan — mengehadkan tempat lukisan boleh muncul (clipPath, clipRect, clipRRect).
  • Mod pengadunan — mengawal pengiraan yang menggabungkan lapisan baharu dengan piksel di bawahnya (BlendMode pada Paint).
  • Lapisan — saveLayer mencipta penimbal luar skrin supaya mod pengadunan digunakan pada keseluruhan kumpulan, bukan satu bentuk sahaja.

Pelajaran ini menggabungkan ketiga-tiganya.

Memotong Kanvas

Dalam CustomPainter.paint, pemotongan mengecilkan kawasan yang boleh dilukis. Segala yang anda lukis selepas pemotongan akan ditopeng kepada kawasan itu sehingga restore() seterusnya.

  • canvas.clipRect(rect) — pemotongan segi empat tepat.
  • canvas.clipRRect(rrect) — pemotongan segi empat tepat berbucu bulat (sangat sesuai untuk imej kecil kad).
  • canvas.clipPath(path) — pemotongan bentuk sewenang-wenangnya.

Sentiasa pasangkan pemotongan dengan save() / restore() supaya pemotongan tidak terbawa ke lukisan seterusnya.

class ClipPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..color = const Color(0xFF2196F3);
    canvas.save();
    final rrect = RRect.fromRectAndRadius(
      Offset.zero & size,
      const Radius.circular(24),
    );
    canvas.clipRRect(rrect);
    // Fills the whole canvas, but only the rounded area shows.
    canvas.drawRect(Offset.zero & size, paint);
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant ClipPainter oldDelegate) => false;
}

Memotong dengan Laluan Sewenang-wenangnya

Untuk topeng bukan segi empat tepat (tiket, gelombang, lencana), bina Path dan hantarkannya kepada clipPath. Bentuk tiket klasik menggunakan dua lengkok cekung pada sisinya.

Tetapkan doAntiAlias: true (nilai lalai) untuk tepi yang licin. Untuk pemotongan beranimasi yang berubah pada setiap bingkai, doAntiAlias: false mungkin sedikit lebih pantas.

Path ticketPath(Size size, double notch) {
  final r = notch;
  return Path()
    ..moveTo(0, 0)
    ..lineTo(size.width, 0)
    ..lineTo(size.width, size.height / 2 - r)
    ..arcToPoint(
      Offset(size.width, size.height / 2 + r),
      radius: Radius.circular(r),
      clockwise: false,
    )
    ..lineTo(size.width, size.height)
    ..lineTo(0, size.height)
    ..lineTo(0, size.height / 2 + r)
    ..arcToPoint(
      Offset(0, size.height / 2 - r),
      radius: Radius.circular(r),
      clockwise: false,
    )
    ..close();
}

Perkara Sebenar yang Dilakukan oleh Mod Pengadunan

BlendMode mentakrifkan formula yang menggabungkan sumber (perkara yang sedang anda lukis) dengan destinasi (piksel yang sudah ada). Nilai lalai ialah BlendMode.srcOver — penggubahan alfa biasa.

Keluarga yang berguna:

  • Porter-Duff (geometri/penopengan): srcIn, dstIn, srcOut, dstATop, clear.
  • Pengiraan warna terpisah: multiply, screen, overlay, plus (cahaya tambahan), difference.

Anda menetapkannya pada Paint: paint.blendMode = BlendMode.multiply.

Mod Pengadunan Memerlukan Lapisan

Inilah perkara penting yang sering terlepas pandang: banyak mod pengadunan (srcIn, dstIn, multiply pada ketelusan dan sebagainya) hanya berfungsi dengan betul apabila terdapat lapisan yang jelas untuk dijadikan destinasi.

canvas.saveLayer(bounds, paint) memperuntukkan penimbal luar skrin. Lukisan antara saveLayer dan restore terkumpul dalam penimbal itu; apabila restore dipanggil, penimbal digubah semula menggunakan mod pengadunan cat lapisan.

Tanpa saveLayer, lukisan srcIn akan menganggap seluruh skrin sebagai destinasi — biasanya memadam lebih banyak daripada yang anda maksudkan.

void paint(Canvas canvas, Size size) {
  final bounds = Offset.zero & size;
  // 1. Open an offscreen layer.
  canvas.saveLayer(bounds, Paint());
  // 2. Destination: a circle.
  canvas.drawCircle(
    size.center(Offset.zero),
    size.shortestSide / 2,
    Paint()..color = const Color(0xFFFFFFFF),
  );
  // 3. Source with srcIn keeps only the overlap with the circle.
  canvas.drawRect(
    bounds,
    Paint()
      ..shader = const LinearGradient(
        colors: [Color(0xFFFF0080), Color(0xFF7928CA)],
      ).createShader(bounds)
      ..blendMode = BlendMode.srcIn,
  );
  // 4. Composite the layer back to the canvas.
  canvas.restore();
}

Menopeng Kecerunan ke dalam Bentuk

Pola daripada babak sebelumnya ialah kaedah lazim untuk ikon berisi kecerunan atau topeng teks:

  • Lukis bentuk topeng legap dahulu (ia menjadi destinasi).
  • Lukis kecerunan dengan BlendMode.srcIn — ia hanya kekal di tempat topeng itu legap.

Terbalikkan peranan dengan dstIn: lukis kecerunan dahulu, kemudian bentuk dengan dstIn supaya hanya kecerunan di bawah bentuk itu dikekalkan. Buat pilihan berdasarkan lapisan yang ingin anda lukis terakhir.

class GradientTextMask extends CustomPainter {
  GradientTextMask(this.label);
  final String label;

  @override
  void paint(Canvas canvas, Size size) {
    final bounds = Offset.zero & size;
    canvas.saveLayer(bounds, Paint());
    final tp = TextPainter(
      text: TextSpan(
        text: label,
        style: const TextStyle(
          fontSize: 64, fontWeight: FontWeight.bold,
          color: Color(0xFFFFFFFF),
        ),
      ),
      textDirection: TextDirection.ltr,
    )..layout();
    tp.paint(canvas, Offset.zero); // destination = glyphs
    canvas.drawRect(
      bounds,
      Paint()
        ..shader = const LinearGradient(
          colors: [Color(0xFF00C6FF), Color(0xFF0072FF)],
        ).createShader(bounds)
        ..blendMode = BlendMode.srcIn, // gradient fills glyphs
    );
    canvas.restore();
  }

  @override
  bool shouldRepaint(covariant GradientTextMask old) => old.label != label;
}

Cahaya Tambahan dengan BlendMode.plus

BlendMode.plus menambahkan saluran warna sumber dan destinasi (dihadkan kepada 1.0). Bentuk terang yang bertindih menjadi lebih terang — sesuai untuk cahaya neon, percikan dan pancaran cahaya.

Gabungkannya dengan MaskFilter.blur untuk melembutkan setiap bentuk menjadi lingkaran cahaya. Oleh sebab plus mengumpulkan kesan, melapiskan beberapa bulatan yang dikaburkan menghasilkan cahaya yang meyakinkan tanpa sebarang aset imej.

void drawGlow(Canvas canvas, Offset c, double r, Color color) {
  final glow = Paint()
    ..color = color
    ..blendMode = BlendMode.plus
    ..maskFilter = const MaskFilter.blur(BlurStyle.normal, 12);
  canvas.drawCircle(c, r, glow);
  // A second, tighter core makes the center read brighter.
  canvas.drawCircle(c, r * 0.5,
    Paint()..color = color..blendMode = BlendMode.plus);
}

Menebuk Lubang dengan BlendMode.clear

Untuk memotong lubang lutsinar melalui lapisan yang telah dilukis, lukis bentuk dengan BlendMode.clear. Ia memadam piksel destinasi (menetapkan alfa kepada 0) di mana-mana sumber meliputinya.

Ini mesti berlaku dalam saveLayer — jika tidak, clear akan menebuk segala yang berada di belakang kanvas, termasuk widget di bawahnya. Kesan sorotan/tindanan dengan potongan ialah penggunaan yang lazim.

void paint(Canvas canvas, Size size) {
  final bounds = Offset.zero & size;
  canvas.saveLayer(bounds, Paint());
  // Dim scrim covering everything.
  canvas.drawRect(bounds, Paint()..color = const Color(0xCC000000));
  // Cut a clear circular "spotlight" through the scrim.
  canvas.drawCircle(
    size.center(Offset.zero),
    size.shortestSide / 4,
    Paint()..blendMode = BlendMode.clear,
  );
  canvas.restore();
}

Cat Lapisan berbanding Cat Setiap Bentuk

Terdapat dua cat berbeza yang digunakan, dan tersalah mencampurkannya ialah pepijat biasa:

  • Cat setiap bentuk (dihantarkan kepada drawCircle, drawRect…) mengawal cara bentuk itu digabungkan dengan kandungan lapisan semasa.
  • Cat lapisan (dihantarkan kepada saveLayer) mengawal cara keseluruhan lapisan yang telah siap digabungkan semula apabila anda memanggil restore(), dan boleh menggunakan opacity atau colorFilter pada kumpulan.

Mahukan satu gelangsar untuk memudarkan keseluruhan kumpulan gubahan secara seragam? Letakkan kelegapan pada cat lapisan, bukan pada setiap bentuk — kelegapan setiap bentuk akan menyebabkan pertindihan saling terlihat.

void paint(Canvas canvas, Size size) {
  final bounds = Offset.zero & size;
  // Group opacity: whole layer fades together.
  final layerPaint = Paint()..color = const Color(0x80FFFFFF);
  canvas.saveLayer(bounds, layerPaint);
  final p = Paint()..color = const Color(0xFFE91E63);
  canvas.drawCircle(const Offset(60, 60), 50, p);
  canvas.drawCircle(const Offset(100, 60), 50, p); // overlap stays solid
  canvas.restore(); // entire pair composited at 50% alpha
}

Gabungkan Pemotongan + Pengadunan + Lapisan

Imej kecil berbucu bulat yang berkabus dengan kilauan kecerunan menggabungkan ketiga-tiga alat mengikut turutan:

  • Potong kepada segi empat tepat berbucu bulat supaya tiada apa-apa terkeluar dari kad.
  • saveLayer supaya kilauan boleh digabungkan dengan foto sebagai satu kumpulan.
  • Lukis foto, kemudian sorotan lembut dengan BlendMode.softLight atau overlay.

Turutan sangat penting: potong dahulu, buka lapisan, lukis destinasi, lukis sumber yang digabungkan, pulihkan, kemudian pulihkan pemotongan.

void paint(Canvas canvas, Size size, ui.Image photo) {
  final bounds = Offset.zero & size;
  canvas.save();
  canvas.clipRRect(
    RRect.fromRectAndRadius(bounds, const Radius.circular(20)),
  );
  canvas.saveLayer(bounds, Paint());
  canvas.drawImageRect(
    photo,
    Offset.zero & Size(photo.width.toDouble(), photo.height.toDouble()),
    bounds,
    Paint(),
  );
  canvas.drawRect(
    bounds,
    Paint()
      ..shader = const LinearGradient(
        begin: Alignment.topLeft, end: Alignment.bottomRight,
        colors: [Color(0x88FFFFFF), Color(0x11000000)],
      ).createShader(bounds)
      ..blendMode = BlendMode.softLight,
  );
  canvas.restore(); // close layer
  canvas.restore(); // close clip
}

Prestasi: Lapisan Bukan Percuma

Setiap saveLayer memperuntukkan tekstur luar skrin dan memaksa laluan penggubahan tambahan — perkara paling mahal yang boleh anda lakukan bagi setiap bingkai dalam pelukis. Gunakannya dengan sengaja apabila perlu, bukan sebagai lalai.

  • Hantarkan bounds sekecil yang mungkin kepada saveLayer; lapisan seluruh skrin jauh lebih mahal daripada lapisan kecil.
  • Utamakan clipRRect biasa + lukisan terus apabila anda sebenarnya tidak memerlukan pengadunan kumpulan.
  • Cache gubahan statik (contohnya melalui ui.PictureRecorder ke dalam ui.Image) dan bukannya membina semula lapisan pada setiap bingkai.
  • Guna semula objek Paint; elakkan peruntukan dalam laluan paint yang kerap digunakan.

Semakan Pantas: Memilih Alat yang Tepat

Anda mahu mengisi glif teks tebal dengan kecerunan linear dalam CustomPainter, dan tiada apa-apa di luar glif boleh diwarnakan. Pendekatan manakah yang betul?

Imbas Kembali

Kini anda boleh menggubah kesan berlapis lanjutan pada Canvas:

  • Pemotongan (clipRect/clipRRect/clipPath) mengehadkan tempat lukisan muncul — sentiasa bungkusnya dalam save()/restore().
  • Mod pengadunan menetapkan cara sumber digabungkan dengan destinasi: srcIn/dstIn untuk penopengan, plus untuk cahaya tambahan, clear untuk lubang potongan, softLight/overlay untuk kilauan.
  • saveLayer memberikan mod pengadunan penimbal destinasi sebenar dan membolehkan anda menggunakan kelegapan kumpulan atau penapis warna melalui cat lapisan.
  • Bezakan cat lapisan daripada cat setiap bentuk, lukis destinasi sebelum sumber, dan pastikan lapisan kecil serta jarang digunakan demi prestasi.

Gunakan lapisan dengan sengaja, lakukan pemotongan apabila anda hanya memerlukan topeng, dan cache gubahan statik.

Percuma untuk bermula

Pelajari Dart dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
22
Pelajaran
88

Soalan Lazim

Adakah pelajaran “Pemotongan, Mod Campuran dan Penggubahan Lapisan” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Pembangunan Aplikasi Mudah Alih Flutter, termasuk “Pemotongan, Mod Campuran dan Penggubahan Lapisan”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Pembangunan Aplikasi Mudah Alih Flutter merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Pemotongan, Mod Campuran dan Penggubahan Lapisan”?

Gunakan laluan pemotongan dan mod campuran untuk menggubah kesan visual berlapis yang canggih. Anda berlatih Pembangunan Aplikasi Mudah Alih Flutter menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Pembangunan Aplikasi Mudah Alih Flutter?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Pembangunan Aplikasi Mudah Alih Flutter di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 3 daripada 4.

Berapa lamakah pelajaran “Pemotongan, Mod Campuran dan Penggubahan Lapisan” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Pembangunan Aplikasi Mudah Alih Flutter ini?

Ya. Setiap pelajaran Pembangunan Aplikasi Mudah Alih Flutter menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. API Canvas: Laluan, Cat dan Pencelup
  2. Membina Widget Carta Tersuai Interaktif
  3. Pemotongan, Mod Campuran dan Penggubahan Lapisan
  4. Ujian Sentuhan dan Pengoptimuman Lukisan Semula
← Kembali ke Pembangunan Aplikasi Mudah Alih Flutter