让用户向SwiftUI视图添加多个图像
我正在使用SwiftUI进行练习,制作一个meme maker,它的标签是从文本字段生成的,可以移动和调整大小。我也希望能够做到这一点,从用户的照片库的图像。我可以得到一张图片,但如果我尝试得到更多,它只会替换第一张图片。我尝试将图像添加到数组中,但是图像将不会显示在MemeImage视图中让用户向SwiftUI视图添加多个图像,swiftui,Swiftui,我正在使用SwiftUI进行练习,制作一个meme maker,它的标签是从文本字段生成的,可以移动和调整大小。我也希望能够做到这一点,从用户的照片库的图像。我可以得到一张图片,但如果我尝试得到更多,它只会替换第一张图片。我尝试将图像添加到数组中,但是图像将不会显示在MemeImage视图中 var body: some View { VStack(spacing: 12) { memeImageView
var body: some View {
VStack(spacing: 12) {
memeImageView
ForEach(0..<(meme.boxCount ?? 0)) { i in
TextField("Statement \(i + 1)", text: $addedLabels[i])
.padding(.horizontal, 8)
.padding(.vertical, 4)
.background(Color.gray.opacity(0.25))
.cornerRadius(5)
.onTapGesture {
self.endEditing()
}
}
.padding(.horizontal)
}.onTapGesture {
self.endEditing()
}
// Gets a new Image
Button {
self.isShowPhotoLibrary = true
addedImages.append(image)
} label: {
Text("Add Image")
.foregroundColor(Color.yellow)
}.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
Spacer()
// Saves Image
Button {
// takes a screenshot and crops it
if let image = memeImageView.takeScreenshot(origin: CGPoint(x: 0, y: UIApplication.shared.windows[0].safeAreaInsets.top + navBarHeight + 1), size: CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height / 2.5)) {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
presentationMode.wrappedValue.dismiss() // dismisses the view
}
}
label: {
Text("Save image")
.foregroundColor(Color.yellow)
}.frame( width: 150, height: 50)
.overlay(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.red, lineWidth: 3)
)
.navigationBarTitle(meme.name ?? "Meme", displayMode: .inline)
.background(NavBarAccessor { navBar in
self.navBarHeight = navBar.bounds.height
})
}
图像属性
@State private var image = UIImage()
钮扣
Button {
self.isShowPhotoLibrary = true
} label: {
Text("Add Image")
.foregroundColor(Color.yellow)
}.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
Button {
self.isShowPhotoLibrary = true
addedImages.append(image)
} label: {
Text("Add Image")
.foregroundColor(Color.yellow)
}.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
var memeImageView: some View {
ZStack {
KFImage(URL(string: meme.url ?? ""))
.placeholder {
ProgressView()
}
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: UIScreen.main.bounds.height / 2.5)
ForEach(addedLabels, id:\.self) { label in
DraggableLabel(text: label)
}
ForEach(0..<addedImages.count) { index in
DraggableImage(image: addedImages[index]!)
}
}
.clipped()
}
MemeUmageView
var memeImageView: some View {
ZStack {
KFImage(URL(string: meme.url ?? ""))
.placeholder {
ProgressView()
}
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: UIScreen.main.bounds.height / 2.5)
ForEach(addedLabels, id:\.self) { label in
DraggableLabel(text: label)
}
DraggableImage(image: image)
}
.clipped()
}
尝试使用数组。我还尝试制作三个按钮,将三个图像相加,每个按钮都作为自己的属性,认为初始属性被覆盖
我的图像阵列
@State private var addedImages = [UIImage?]()
钮扣
Button {
self.isShowPhotoLibrary = true
} label: {
Text("Add Image")
.foregroundColor(Color.yellow)
}.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
Button {
self.isShowPhotoLibrary = true
addedImages.append(image)
} label: {
Text("Add Image")
.foregroundColor(Color.yellow)
}.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
var memeImageView: some View {
ZStack {
KFImage(URL(string: meme.url ?? ""))
.placeholder {
ProgressView()
}
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: UIScreen.main.bounds.height / 2.5)
ForEach(addedLabels, id:\.self) { label in
DraggableLabel(text: label)
}
ForEach(0..<addedImages.count) { index in
DraggableImage(image: addedImages[index]!)
}
}
.clipped()
}
DragImageView:
import SwiftUI
struct DragImageView: View {
//===================
// MARK: Properties
//===================
@State private var addedImages = [UIImage?]()
@State private var isShowPhotoLibrary = false
@State private var image = UIImage()
var body: some View {
VStack(spacing: 12) {
imageView
}
// Gets a new Image
Button {
self.isShowPhotoLibrary = true
addedImages.append(image)
} label: {
Text("Add Image")
.foregroundColor(Color.yellow)
}.sheet(isPresented: $isShowPhotoLibrary) {
ImagePicker(sourceType: .photoLibrary, selectedImage: self.$image)
}
Spacer()
}
var imageView: some View {
ZStack {
DraggableImage(image: image)
}
//.clipped()
}
// This will dismiss the keyboard
private func endEditing() {
UIApplication.shared.endEditing()
}
}
// Allows fot the keyboard to be dismissed
extension UIApplication {
func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
可拖动图像:
import SwiftUI
struct DraggableImage: View {
// Drag Gesture
@State private var currentPosition: CGSize = .zero
@State private var newPosition: CGSize = .zero
// Roation Gesture
@State private var rotation: Double = 0.0
// Scale Gesture
@State private var scale: CGFloat = 1.0
// The different states the frame of the label could be
private enum WidthState: Int {
case full, half, third, fourth
}
@State private var widthState: WidthState = .full
@State private var currentWidth: CGFloat = 100 //UIScreen.main.bounds.width
var image: UIImage
var body: some View {
VStack {
Image(uiImage: self.image)
.resizable()
.scaledToFill()
.frame(width: self.currentWidth)
.lineLimit(nil)
}
.scaleEffect(scale) // Scale based on our state
.rotationEffect(Angle.degrees(rotation)) // Rotate based on the state
.offset(x: self.currentPosition.width, // Offset from the drag difference from it's current position
y: self.currentPosition.height)
.gesture(
// Two finger rotation
RotationGesture()
.onChanged { angle in
self.rotation = angle.degrees // keep track of the angle for state
}
// We want it to work with the scale effect, so they could either scale and rotate at the same time
.simultaneously(with:
MagnificationGesture()
.onChanged { scale in
self.scale = scale.magnitude // Keep track of the scale
})
// Update the drags new position to be wherever it was last dragged to. (we don't want to reset it back to it's current position)
.simultaneously(with: DragGesture()
.onChanged { value in
self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width,
height: value.translation.height + self.newPosition.height)
}
.onEnded { value in
self.newPosition = self.currentPosition
})
)
/// Have to do double tap first or else it will never work with the single tap
.onTapGesture(count: 2) {
// Update our widthState to be the next on in the 'enum', or start back at .full
self.widthState = WidthState(rawValue: self.widthState.rawValue + 1) ?? .full
self.currentWidth = UIScreen.main.bounds.width / CGFloat(self.widthState.rawValue)
}
}
}
图像选择器:
import UIKit
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
var sourceType: UIImagePickerController.SourceType = .photoLibrary
@Binding var selectedImage: UIImage
@Environment(\.presentationMode) private var presentationMode
func makeUIViewController(context: UIViewControllerRepresentableContext<ImagePicker>) -> UIImagePickerController {
let imagePicker = UIImagePickerController()
imagePicker.allowsEditing = false
imagePicker.sourceType = sourceType
imagePicker.delegate = context.coordinator
return imagePicker
}
func updateUIViewController(_ uiViewController: UIImagePickerController, context: UIViewControllerRepresentableContext<ImagePicker>) {
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var parent: ImagePicker
init(_ parent: ImagePicker) {
self.parent = parent
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
parent.selectedImage = image
}
parent.presentationMode.wrappedValue.dismiss()
}
}
}
导入UIKit
导入快捷键
结构图像选择器:UIViewControllerRepresentable{
变量sourceType:UIImagePickerController.sourceType=.photoLibrary
@绑定变量SelecteImage:UIImage
@环境(\.presentationMode)私有变量presentationMode
func makeUIViewController(上下文:UIViewControllerRepresentableContext)->UIImagePickerController{
让imagePicker=UIImagePickerController()
imagePicker.allowsEditing=false
imagePicker.sourceType=源类型
imagePicker.delegate=context.coordinator
返回图像选择器
}
func updateUIViewController(uViewController:UIImagePickerController,上下文:UIViewControllerRepresentableContext){
}
func makeCoordinator()->Coordinator{
协调员(自我)
}
最终类协调器:NSObject、UIImagePickerControllerDelegate、UINavigationControllerDelegate{
var父对象:ImagePicker
init(uu父对象:ImagePicker){
self.parent=parent
}
func imagePickerController(picker:UIImagePickerController,didFinishPickingMediaWithInfo:[UIImagePickerController.InfoKey:Any]){
如果让image=info[UIImagePickerController.InfoKey.originalImage]作为?UIImage{
parent.selectedImage=image
}
parent.presentationMode.wrappedValue.disclease()
}
}
}
我应该加上这一点是为了制作模因,这样用户拾取的图像就会出现在我保存到相机卷的视图的顶部。我不是100%清楚确切的期望输出应该是什么,但这应该让您开始(解释如下):
结构DragImageView:视图{
//===================
//马克:财产
//===================
@国家私有变量addedImages=[UIImage]()
@国家私有变量isShowPhotoLibrary=false
var bindingForImage:绑定{
在中绑定{()->UIImage
返回addedImages.last??UIImage()
}在中设置:{(新图像)
addedImages.append(新图像)
打印(“图像:\(addedImages.count)”)
}
}
var body:一些观点{
VStack(间距:12){
图像视图
}
//获取新图像
钮扣{
self.isShowPhotoLibrary=true
}标签:{
文本(“添加图像”)
.foregroundColor(颜色.黄色)
}.sheet(显示:$isShowPhotoLibrary){
ImagePicker(源类型:.photoLibrary,选择图像:bindingForImage)
}
垫片()
}
var-imageView:一些视图{
VStack{
ForEach(addedImages,id:\.self){image in
DragTableImage(图像:图像)
}
}
}
//这将关闭键盘
私有函数endEditing(){
UIApplication.shared.endEditing()
}
}
addedImages
现在是一个非可选的UIImages
图像选择器有一个自定义绑定。当它接收到一个新图像时,它会将其附加到数组的末尾
在
var-imageView
中,有一个VStack
而不是ZStack
,这样可以显示多个图像(而不是堆叠在一起),并有一个ForEach
循环来遍历图像。你能显示你用数组尝试的代码吗?你肯定需要一个数组和一个ForEach
,就像你在addedLabels中使用的那样是的,我将使用相同的按钮向你展示最新的方法。你在编辑中没有显示所有的代码。您在哪里定义了addedImages
?很抱歉,我现在已经添加了它。调用memeImageView
的位置在哪里?你能举一个最小的、可重复的例子吗?非常感谢。我欠你的!这正是我想做的!