π· Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ Π²ΡΡΠ°Π²ΠΊΠΈ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ ΠΈΠ· Π±ΡΡΠ΅ΡΠ° ΠΎΠ±ΠΌΠ΅Π½Π° Π² 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