πŸ“· РСализация вставки ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° Π² Flutter: кроссплатформСнная дСмонстрация с PasteSnap

πŸ“· РСализация вставки ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° Π² Flutter: кроссплатформСнная дСмонстрация с PasteSnap

FlutterPulse

Π­Ρ‚Π° ΡΡ‚Π°Ρ‚ΡŒΡ ΠΏΠ΅Ρ€Π΅Π²Π΅Π΄Π΅Π½Π° ΡΠΏΠ΅Ρ†ΠΈΠ°Π»ΡŒΠ½ΠΎ для ΠΊΠ°Π½Π°Π»Π° FlutterPulse. Π’ этом ΠΊΠ°Π½Π°Π»Π΅ Π²Ρ‹ Π½Π°ΠΉΠ΄Ρ‘Ρ‚Π΅ ΠΌΠ½ΠΎΠ³ΠΎ интСрСсных Π²Π΅Ρ‰Π΅ΠΉ, связанных с Flutter. НС Π·Π°Π±Ρ‹Π²Π°ΠΉΡ‚Π΅ ΠΏΠΎΠ΄ΠΏΠΈΡΡ‹Π²Π°Ρ‚ΡŒΡΡ! πŸš€

БлоТности с вставкой ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ Π² Flutter? Π£Π·Π½Π°ΠΉΡ‚Π΅, ΠΊΠ°ΠΊ я создал ΠΊΡ€ΠΎΡΡΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ΅Π½Π½ΡƒΡŽ Π΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€Π°Ρ†ΠΈΡŽ с использованиСм MethodChannel ΠΈ BLoC для вставки ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° πŸš€

Π’Π²Π΅Π΄Π΅Π½ΠΈΠ΅

Flutter ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ΠΈΡ‚ для кроссплатформСнных ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, Π½ΠΎ Π΅Π³ΠΎ класс Clipboard ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ тСкст, Π° Π½Π΅ изобраТСния. Для ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΌΠ½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΠΈ ΠΌΠΎΠ³Π»ΠΈ Π²ΡΡ‚Π°Π²Π»ΡΡ‚ΡŒ изобраТСния Π² интСрфСйс Ρ‡Π°Ρ‚Π° β€” распространённая функция Π² мСссСндТСрах. ΠŸΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Ρƒ Flutter Π½Π΅Ρ‚ Π½Π°Ρ‚ΠΈΠ²Π½ΠΎΠΉ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ, я использовал MethodChannel для ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΈ ΠΊΠΎΠ΄Π°, спСцифичного для iOS ΠΈ Android. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ это, я создал PasteSnap, дСмонстрационноС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, сосрСдоточСнноС Π½Π° вставкС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° Π² интСрфСйсС, ΠΏΠΎΡ…ΠΎΠΆΠ΅ΠΌ Π½Π° Ρ‡Π°Ρ‚.

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠ°: Π‘ΡƒΡ„Π΅Ρ€ ΠΎΠ±ΠΌΠ΅Π½Π° Flutter ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ тСкст

Класс Clipboard Π² Flutter (ΠΈΠ· ΠΏΠ°ΠΊΠ΅Ρ‚Π° package:flutter/services) ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ справляСтся с тСкстом, Π½ΠΎ Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ изобраТСния. МнС Π½ΡƒΠΆΠ½ΠΎ Π±Ρ‹Π»ΠΎ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ вставку ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ Π² интСрфСйс Ρ‡Π°Ρ‚Π°, ΠΊΠ°ΠΊ Π² WhatsApp, Ρ‡Π΅Π³ΠΎ Flutter Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π½Π°Ρ‚ΠΈΠ²Π½ΠΎ. Π― Ρ€Π΅ΡˆΠΈΠ» эту ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡƒ, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹Π΅ API для iOS ΠΈ Android, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Ρ‘Π½Π½Ρ‹Π΅ ΠΊ Flutter Ρ‡Π΅Ρ€Π΅Π· MethodChannel. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΎΠ΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ это, Π½Π΅ раскрывая основной ΠΏΡ€ΠΎΠ΅ΠΊΡ‚, я создал PasteSnap β€” минимальноС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, сосрСдоточСнноС Π½Π° вставкС ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π°.

РСшСниС: Нативная интСграция с MethodChannel

ΠŸΠΎΠ΄Ρ…ΠΎΠ΄ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Ρ‚Ρ€ΠΈ ΠΊΠ»ΡŽΡ‡Π΅Π²Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°:

  • iOS: ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° с использованиСм UIPasteboard Π² AppDelegate.swift.
  • Android: Доступ ΠΊ изобраТСниям ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° с использованиСм ClipboardManager Π² MainActivity.kt.
  • Flutter: ИспользованиС MethodChannel для связи ΠΌΠ΅ΠΆΠ΄Ρƒ Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌ слоСм ΠΈ слоСм Dart, интСграция Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Π² ChatBloc ΠΈ ChatScreen.

Π­Ρ‚ΠΎ кроссплатформСнноС Ρ€Π΅ΡˆΠ΅Π½ΠΈΠ΅ обСспСчиваСт Π±Π΅ΡΠΏΠ΅Ρ€Π΅Π±ΠΎΠΉΠ½ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‚Ρƒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΊΠ°ΠΊ Π½Π° iOS, Ρ‚Π°ΠΊ ΠΈ Π½Π° Android, ΠΊΠ°ΠΊ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ Π² PasteSnap.

Пошаговая рСализация

Настройка ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Flutter

Π― настроил ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ Flutter с ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌΠΈ зависимостями Π² pubspec.yaml. Π­Ρ‚ΠΈ ΠΏΠ°ΠΊΠ΅Ρ‚Ρ‹ ΠΏΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²Π»ΡΡŽΡ‚ инструмСнты, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ для управлСния состояниСм ΠΈ Ρ€Π°Π±ΠΎΡ‚Ρ‹ с Ρ„Π°ΠΉΠ»Π°ΠΌΠΈ.

dependencies:
flutter:
sdk: flutter
flutter_bloc: ^8.1.0
equatable: ^2.0.0
path_provider: ^2.1.5
  • flutter_bloc ΠΈ equatable для Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ шаблона BLoC для управлСния состояниСм.
  • path_provider ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ с доступом ΠΊ Ρ„Π°ΠΉΠ»ΠΎΠ²ΠΎΠΉ систСмС (хотя Π² ΠΏΡ€ΠΈΠ²Π΅Π΄Ρ‘Π½Π½Ρ‹Ρ… Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Π°Ρ… ΠΎΠ½ Π½Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ, ΠΎΠ½ являСтся Ρ‡Π°ΡΡ‚ΡŒΡŽ ΠΏΠΎΠ»Π½ΠΎΠ³ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°).

Π¨Π°Π³ 1: ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ MethodChannel Π² Flutter

Π’ вашСм ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅ Flutter ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚Π΅ MethodChannel Π² классС ChatBloc. Π­Ρ‚ΠΎΡ‚ ΠΊΠ°Π½Π°Π» Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒΡΡ для связи с Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌ ΠΊΠΎΠ΄ΠΎΠΌ для получСния ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π°.

import 'dart:typed_data';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/services.dart';

part 'chat_bloc_event.dart';
part 'chat_bloc_state.dart';

class ChatBloc extends Bloc<ChatEvent, ChatState> {
static const _imageChannel = MethodChannel('clipboard/image');

ChatBloc() : super(const ChatState(text: '')) {
on<PasteImageEvent>(_onPasteImage);
on<UpdateTextEvent>(_onUpdateText);
on<SendMessageEvent>(_onSendMessage);
}

Future<void> _onPasteImage(PasteImageEvent event, Emitter<ChatState> emit) async {
try {
final imageData = await _imageChannel.invokeMethod('getClipboardImage');
if (imageData != null && imageData is Uint8List) {
emit(ChatState(
text: state.text,
previewImage: imageData,
messages: state.messages,
));
} else {
print('No image data found in clipboard');
}
} catch (e) {
print('Failed to get clipboard image: $e');
}
}
}

ПояснСниС:

  • Канал _imageChannel ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½ ΠΊΠ°ΠΊ MethodChannel для связи с Π½Π°Ρ‚ΠΈΠ²Π½Ρ‹ΠΌ слоСм.
  • Π’ _onPasteImage вызываСтся ΠΌΠ΅Ρ‚ΠΎΠ΄ getClipboardImage, оТидаСтся Uint8List (Π΄Π°Π½Π½Ρ‹Π΅ изобраТСния). ΠŸΡ€ΠΈ ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ обновляСтся previewImage Π² состоянии.

Π¨Π°Π³ 2: РСализация для iOS (AppDelegate.swift)

Π’ AppDelegate.swift настройтС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² для ΠΏΡ€ΠΎΡΠ»ΡƒΡˆΠΈΠ²Π°Π½ΠΈΡ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΈΠ· Flutter. Когда вызываСтся ΠΌΠ΅Ρ‚ΠΎΠ΄ getClipboardImage, ΠΈΠ·Π²Π»Π΅ΠΊΠ°ΠΉΡ‚Π΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΠΉΡ‚Π΅ Π΅Π³ΠΎ Π² Π²ΠΈΠ΄Π΅ массива Π±Π°ΠΉΡ‚ΠΎΠ².

import UIKit
import Flutter

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller = window?.rootViewController as! FlutterViewController
let imageChannel = FlutterMethodChannel(name: "clipboard/image",
binaryMessenger: controller.binaryMessenger)
imageChannel.setMethodCallHandler { [weak self] (call, result) in
if call.method == "getClipboardImage" {
self?.getClipboardImage(result: result)
} else {
result(FlutterMethodNotImplemented)
}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}

private func getClipboardImage(result: FlutterResult) {
if let image = UIPasteboard.general.image,
let data = image.jpegData(compressionQuality: 0.9) {
result(data)
} else {
result(nil)
}
}
}

ОбъяснСниС:

  • UIPasteboard.general.image провСряСт, содСрТит Π»ΠΈ Π±ΡƒΡ„Π΅Ρ€ ΠΎΠ±ΠΌΠ΅Π½Π° ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅.
  • Если ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ, ΠΎΠ½ΠΎ прСобразуСтся Π² JPEG-Π΄Π°Π½Π½Ρ‹Π΅ с качСством сТатия 0.9 для ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡ Ρ€Π°Π·ΠΌΠ΅Ρ€Π°.
  • Массив Π±Π°ΠΉΡ‚ΠΎΠ² (Data) возвращаСтся Π² Flutter Ρ‡Π΅Ρ€Π΅Π· result. Если ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ отсутствуСт, возвращаСтся nil.

Π¨Π°Π³ 3: РСализация для Android (MainActivity.kt)

Π’ MainActivity.kt настройтС ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² для ΠΏΡ€ΠΎΡΠ»ΡƒΡˆΠΈΠ²Π°Π½ΠΈΡ Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² ΠΈΠ· Flutter. Когда вызываСтся ΠΌΠ΅Ρ‚ΠΎΠ΄ getClipboardImage, ΠΈΠ·Π²Π»Π΅ΠΊΠ°ΠΉΡ‚Π΅ ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΠΉΡ‚Π΅ Π΅Π³ΠΎ Π² Π²ΠΈΠ΄Π΅ массива Π±Π°ΠΉΡ‚ΠΎΠ².

package com.example.paste_snap_demo

import android.content.ClipboardManager
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import java.io.ByteArrayOutputStream

class MainActivity : FlutterActivity() {
private val CHANNEL = "clipboard/image"

override fun configureFlutterEngine(flutterEngine: io.flutter.embedding.engine.FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
.setMethodCallHandler { call, result ->
if (call.method == "getClipboardImage") {
val imageBytes = getClipboardImage()
if (imageBytes != null) {
result.success(imageBytes)
} else {
result.success(null)
}
} else {
result.notImplemented()
}
}
}

private fun getClipboardImage(): ByteArray? {
val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
if (!clipboard.hasPrimaryClip()) {
return null
}

val clipData = clipboard.primaryClip
if (clipData != null && clipData.itemCount > 0) {
val item = clipData.getItemAt(0)
val uri = item.uri

if (uri != null) {
try {
val inputStream = contentResolver.openInputStream(uri)
val bitmap = android.graphics.BitmapFactory.decodeStream(inputStream)
inputStream?.close()
if (bitmap != null) {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream)
val byteArray = stream.toByteArray()
bitmap.recycle()
stream.close()
return byteArray
}
} catch (e: Exception) {
e.printStackTrace()
return null
}
}
}
return null
}
}

ОбъяснСниС:

  • ClipboardManager провСряСт, содСрТит Π»ΠΈ Π±ΡƒΡ„Π΅Ρ€ ΠΎΠ±ΠΌΠ΅Π½Π° основной ΠΊΠ»ΠΈΠΏ.
  • Если Π½Π°ΠΉΠ΄Π΅Π½ ΠΊΠ»ΠΈΠΏ с URI, ΠΎΠ½ прСобразуСтся Π² Bitmap с использованиСм contentResolver.
  • Π‘ΠΈΡ‚ΠΌΠ°ΠΏ сТимаСтся Π² JPEG с качСством 90% ΠΈ возвращаСтся Π² Π²ΠΈΠ΄Π΅ массива Π±Π°ΠΉΡ‚ΠΎΠ². Если ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠ΅ отсутствуСт, возвращаСтся null.

Π¨Π°Π³ 4: ОбновлСниС интСрфСйса Flutter

Π’ chat_screen.dart, ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚Π΅ интСрфСйс для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ вставки ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ Ρ‡Π΅Ρ€Π΅Π· ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΎΠ΅ контСкстноС мСню Π² TextField, ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ _handlePaste, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ запускаСт дСйствиС вставки изобраТСния. Π’ΠΎΡ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰Π°Ρ Ρ‡Π°ΡΡ‚ΡŒ интСрфСйса:

// ΠœΠ΅Ρ‚ΠΎΠ΄ для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ° вставки
void _handlePaste() {
context.read<ChatBloc>().add(PasteImageEvent());
}

// TextField с ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΡΠΊΠΈΠΌ контСкстным мСню для вставки
TextField(
controller: _messageController,
decoration: const InputDecoration(
hintText: 'Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сообщСниС...',
border: InputBorder.none,
hintStyle: TextStyle(
color: PasteSnapColors.textSecondary,
fontSize: 15,
),
contentPadding: EdgeInsets.symmetric(vertical: 10),
),
maxLines: 5,
minLines: 1,
style: const TextStyle(
color: PasteSnapColors.textPrimary,
fontSize: 15,
),
textCapitalization: TextCapitalization.sentences,
contextMenuBuilder: (context, editableTextState) {
return AdaptiveTextSelectionToolbar.buttonItems(
anchors: editableTextState.contextMenuAnchors,
buttonItems: [
ContextMenuButtonItem(
label: 'Π’ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ',
onPressed: () {
ContextMenuController.removeAny();
_handlePaste();
},
),
],
);
},
),

ОбъяснСниС:

  • ΠœΠ΅Ρ‚ΠΎΠ΄ _handlePaste: ΠžΡ‚ΠΏΡ€Π°Π²Π»ΡΠ΅Ρ‚ событиС PasteImageEvent Π² ChatBloc, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ Π·Π°Ρ‚Π΅ΠΌ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ ΠΈΠ·Π²Π»Π΅Ρ‡Π΅Π½ΠΈΠ΅ изобраТСния ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° Ρ‡Π΅Ρ€Π΅Π· MethodChannel.
  • ΠšΠΎΠ½Ρ‚Π΅ΠΊΡΡ‚Π½ΠΎΠ΅ мСню TextField: Бвойство contextMenuBuilder настраиваСт контСкстноС мСню TextField, добавляя Π² Π½Π΅Π³ΠΎ ΠΎΠΏΡ†ΠΈΡŽ Π’ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ, которая Π²Ρ‹Π·Ρ‹Π²Π°Π΅Ρ‚ _handlePaste() ΠΏΡ€ΠΈ Π½Π°ΠΆΠ°Ρ‚ΠΈΠΈ.
  • ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅: Бвойство hintText динамичСски измСняСтся Π² зависимости ΠΎΡ‚ наличия ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ просмотра изобраТСния (Π½Π΅ ΠΏΠΎΠΊΠ°Π·Π°Π½ΠΎ здСсь для краткости, Π½ΠΎ доступно Π½Π° GitHub).

Визуализация Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°

ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅, ΠΊΠ°ΠΊ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ PasteSnap:

Π’Ρ‹Π²ΠΎΠ΄: ΠœΡ‹ ΡΠΏΡ€Π°Π²ΠΈΠ»ΠΈΡΡŒ! πŸŽ‰ Π’ΠΏΠ΅Ρ€Ρ‘Π΄! πŸš€

РСализация вставки ΠΈΠ·ΠΎΠ±Ρ€Π°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡƒΡ„Π΅Ρ€Π° ΠΎΠ±ΠΌΠ΅Π½Π° Π² Flutter с использованиСм MethodChannel ΠΈ BLoC Π±Ρ‹Π»Π° ΡƒΠ²Π»Π΅ΠΊΠ°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠΉ Π·Π°Π΄Π°Ρ‡Π΅ΠΉ. PasteSnap дСмонстрируСт, ΠΊΠ°ΠΊ эта функция ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ прилоТСния с ΠΏΠΎΡ‚Ρ€Π΅Π±Π½ΠΎΡΡ‚ΡŒΡŽ Π² ΠΎΠ±ΠΌΠ΅Π½Π΅ изобраТСниями, ΠΏΡ€ΠΈ этом сохраняя Ρ‡ΠΈΡΡ‚ΡƒΡŽ Π°Ρ€Ρ…ΠΈΡ‚Π΅ΠΊΡ‚ΡƒΡ€Ρƒ. ΠŸΠΎΡΠΌΠΎΡ‚Ρ€ΠΈΡ‚Π΅ ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ GitHub , ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉΡ‚Π΅ Π΅Π³ΠΎ ΠΈ Π½Π°ΠΏΠΈΡˆΠΈΡ‚Π΅ свои мысли Π² коммСнтариях β€” я Π½Π΅ ΠΌΠΎΠ³Ρƒ Π΄ΠΎΠΆΠ΄Π°Ρ‚ΡŒΡΡ вашСго ΠΎΡ‚Π²Π΅Ρ‚Π°! πŸ’¬

Π Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ ΠΊΠΎΠ΄Π°

Π˜Π·ΡƒΡ‡ΠΈΡ‚Π΅ ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ PasteSnap Π½Π° GitHub: PasteSnap GitHub

Report Page