- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想要一个向用户显示图像的 View 。通过拖动角点,我希望他能够选择裁剪矩形。
因为输入图像的尺寸可能比屏幕大,所以我想使用纵横比适合作为图像的内容模式。
我遇到的问题是,在确定裁剪矩形相对于图像原始尺寸的尺寸时,我不知道如何考虑内容模式引起的位移。
这在视频中可能更容易解释:
如您所见,圆圈位置的上下文是整个 View 。我想改用调整后图像的坐标系。对于此转换,我需要外部 View 的大小与调整后的图像之间的差异。
所以问题是:如何根据调整大小的图像获得用户选择的矩形的正确测量值?
import SwiftUI
struct CropImageViewTest: View {
var currentImage: Image
@State private var currentPositionTopLeft: CGPoint = .zero
@State private var newPositionTopLeft: CGPoint = .zero
@State private var currentPositionTopRight: CGPoint = .zero
@State private var newPositionTopRight: CGPoint = .zero
@State private var currentPositionBottomLeft: CGPoint = .zero
@State private var newPositionBottomLeft: CGPoint = .zero
@State private var currentPositionBottomRight: CGPoint = .zero
@State private var newPositionBottomRight: CGPoint = .zero
var body: some View {
ZStack {
VStack {
Text("Top left: \(currentPositionTopLeft.x) | \(currentPositionTopLeft.y)")
Text("Top right: \(currentPositionTopRight.x) | \(currentPositionTopRight.y)")
Text("Bottom left: \(currentPositionBottomLeft.x) | \(currentPositionBottomLeft.y)")
Text("Bottom right: \(currentPositionBottomRight.x) | \(currentPositionBottomRight.y)")
Spacer()
currentImage
.resizable()
.aspectRatio(1 , contentMode: .fit)
.background(Color.red)
Spacer()
Group {
Button(action: {
// TODO: Crop it
}) {
Image(systemName: "checkmark").resizable().frame(width: 24, height: 24)
.padding(20)
.background(Color(Colors.getColor(Colors.colorSboBlue)))
.foregroundColor(Color.white)
}.clipShape(Circle())
.shadow(radius: 4)
}
}
getCorners()
}
}
private func getCorners() -> some View{
return
HStack {
VStack {
ZStack {
GeometryReader { geometry in
Path { path in
path.move(to: self.currentPositionTopLeft)
path.addLine(
to: .init(
x: self.currentPositionTopRight.x + geometry.size.width,
y: self.currentPositionTopRight.y
)
)
path.addLine(
to: .init(
x: self.currentPositionBottomRight.x + geometry.size.width,
y: self.currentPositionBottomRight.y + geometry.size.height
)
)
path.addLine(
to: .init(
x: self.currentPositionBottomLeft.x,
y: self.currentPositionBottomLeft.y + geometry.size.height
)
)
path.addLine(
to: .init(
x: self.currentPositionTopLeft.x,
y: self.currentPositionTopLeft.y
)
)
}
.stroke(Color.blue, lineWidth: CGFloat(1))
}
Circle().foregroundColor(Color.blue).frame(width: 24, height: 24)
.offset(x: self.currentPositionTopLeft.x, y: self.currentPositionTopLeft.y)
.gesture(DragGesture()
.onChanged { value in
self.currentPositionTopLeft = CGPoint(x: value.translation.width + self.newPositionTopLeft.x, y: value.translation.height + self.newPositionTopLeft.y)
}
.onEnded { value in
self.currentPositionTopLeft = CGPoint(x: value.translation.width + self.newPositionTopLeft.x, y: value.translation.height + self.newPositionTopLeft.y)
self.newPositionTopLeft = self.currentPositionTopLeft
print(self.currentPositionTopLeft)
print(self.newPositionTopLeft)
}
)
.opacity(0.5)
.position(CGPoint(x: 0, y: 0))
GeometryReader { geometry in
Circle().foregroundColor(Color.blue).frame(width: 24, height: 24)
.offset(x: self.currentPositionTopRight.x, y: self.currentPositionTopRight.y)
.gesture(DragGesture()
.onChanged { value in
self.currentPositionTopRight = CGPoint(x: value.translation.width + self.newPositionTopRight.x, y: value.translation.height + self.newPositionTopRight.y)
}
.onEnded { value in
self.currentPositionTopRight = CGPoint(x: value.translation.width + self.newPositionTopRight.x, y: value.translation.height + self.newPositionTopRight.y)
self.newPositionTopRight = self.currentPositionTopRight
print(self.currentPositionTopRight)
print(self.newPositionTopRight)
}
)
.opacity(0.5)
.position(CGPoint(x: geometry.size.width, y: 0))
}
GeometryReader { geometry in
Circle().foregroundColor(Color.blue).frame(width: 24, height: 24)
.offset(x: self.currentPositionBottomLeft.x, y: self.currentPositionBottomLeft.y)
.gesture(DragGesture()
.onChanged { value in
self.currentPositionBottomLeft = CGPoint(x: value.translation.width + self.newPositionBottomLeft.x, y: value.translation.height + self.newPositionBottomLeft.y)
}
.onEnded { value in
self.currentPositionBottomLeft = CGPoint(x: value.translation.width + self.newPositionBottomLeft.x, y: value.translation.height + self.newPositionBottomLeft.y)
self.newPositionBottomLeft = self.currentPositionBottomLeft
print(self.currentPositionBottomLeft)
print(self.newPositionBottomLeft)
}
)
.opacity(0.5)
.position(CGPoint(x: 0, y: geometry.size.height))
}
GeometryReader { geometry in
Circle().foregroundColor(Color.blue).frame(width: 24, height: 24)
.offset(x: self.currentPositionBottomRight.x, y: self.currentPositionBottomRight.y)
.gesture(DragGesture()
.onChanged { value in
self.currentPositionBottomRight = CGPoint(x: value.translation.width + self.newPositionBottomRight.x, y: value.translation.height + self.newPositionBottomRight.y)
}
.onEnded { value in
self.currentPositionBottomRight = CGPoint(x: value.translation.width + self.newPositionBottomRight.x, y: value.translation.height + self.newPositionBottomRight.y)
self.newPositionBottomRight = self.currentPositionBottomRight
print(self.currentPositionBottomRight)
print(self.newPositionBottomRight)
}
)
.opacity(0.5)
.position(CGPoint(x: geometry.size.width, y: geometry.size.height))
}
}
Spacer()
}
Spacer()
}
}
}
如果您没有示例图片,您可以这样调用 View :
CropImageViewTest(currentImage: Image(systemName: "camera.fill"))
我添加了红色背景,以便您可以看到图像的限制。
如果当前方法不是“最快捷”的方法,我也愿意接受完全不同的方法。
提前致谢!
编辑:
我有可用的 UIImage(SwiftUI)图像源自。如果这有助于确定正确的测量值。
更新:
如果我像这样使用裁剪矩形作为图像的叠加层:
currentImage
.resizable()
.aspectRatio(1 , contentMode: .fit)
.overlay(getCorners())
它确实有效。尽管如此,仍然存在每个角定义其起始位置为 (0|0) 的问题。我想相对于图像的左上角定义位置。
最佳答案
好的,终于解决了。
1.) 我使用带有矩形和可拖动角的 View 作为图像的覆盖。这样,矩形和角的原点就是图像,而不是周围的 View 。从这里得到灵感:https://swiftui-lab.com/geometryreader-to-the-rescue/
2.) 仍然存在每个角都将其原点 (0|0) 定义为其初始位置的问题。我通过使用
解决了这个问题.position(CGPoint(x: 0, y: 0))
并使用onAppear
放置坐标。
这会导致应用程序正确计算相对于调整大小的图像的坐标:
我还在自定义 View 中封装了矩形和角,从而产生了这段代码:
Root View :
import SwiftUI
struct CropImageViewTest: View {
var currentImage: Image
@State private var currentPositionTopLeft: CGPoint = .zero
@State private var newPositionTopLeft: CGPoint = .zero
@State private var currentPositionTopRight: CGPoint = .zero
@State private var newPositionTopRight: CGPoint = .zero
@State private var currentPositionBottomLeft: CGPoint = .zero
@State private var newPositionBottomLeft: CGPoint = .zero
@State private var currentPositionBottomRight: CGPoint = .zero
@State private var newPositionBottomRight: CGPoint = .zero
var body: some View {
ZStack {
VStack {
Text("Top left: \(currentPositionTopLeft.x) | \(currentPositionTopLeft.y)")
Text("Top right: \(currentPositionTopRight.x) | \(currentPositionTopRight.y)")
Text("Bottom left: \(currentPositionBottomLeft.x) | \(currentPositionBottomLeft.y)")
Text("Bottom right: \(currentPositionBottomRight.x) | \(currentPositionBottomRight.y)")
Spacer()
currentImage
.resizable()
.aspectRatio(1 , contentMode: .fit)
.overlay(getCorners())
Spacer()
Group {
Button(action: {
// TODO: Crop it
}) {
Image(systemName: "checkmark").resizable().frame(width: 24, height: 24)
.padding(20)
.background(Color(Colors.getColor(Colors.colorSboBlue)))
.foregroundColor(Color.white)
}.clipShape(Circle())
.shadow(radius: 4)
}
}
}
}
private func getCorners() -> some View{
return
HStack {
VStack {
ZStack {
CropImageViewRectangle(
currentPositionTopLeft: self.$currentPositionTopLeft,
currentPositionTopRight: self.$currentPositionTopRight,
currentPositionBottomLeft: self.$currentPositionBottomLeft,
currentPositionBottomRight: self.$currentPositionBottomRight
)
GeometryReader { geometry in
CropImageViewRectangleCorner(
currentPosition: self.$currentPositionTopLeft,
newPosition: self.$newPositionTopLeft,
displacementX: 0,
displacementY: 0
)
CropImageViewRectangleCorner(
currentPosition: self.$currentPositionTopRight,
newPosition: self.$newPositionTopRight,
displacementX: geometry.size.width,
displacementY: 0
)
CropImageViewRectangleCorner(
currentPosition: self.$currentPositionBottomLeft,
newPosition: self.$newPositionBottomLeft,
displacementX: 0,
displacementY: geometry.size.height
)
CropImageViewRectangleCorner(
currentPosition: self.$currentPositionBottomRight,
newPosition: self.$newPositionBottomRight,
displacementX: geometry.size.width,
displacementY: geometry.size.height
)
}
}
Spacer()
}
Spacer()
}
}
}
矩形:
import SwiftUI
struct CropImageViewRectangle: View {
@Binding var currentPositionTopLeft: CGPoint
@Binding var currentPositionTopRight: CGPoint
@Binding var currentPositionBottomLeft: CGPoint
@Binding var currentPositionBottomRight: CGPoint
var body: some View {
GeometryReader { geometry in
Path { path in
path.move(to: self.currentPositionTopLeft)
path.addLine(
to: .init(
x: self.currentPositionTopRight.x,
y: self.currentPositionTopRight.y
)
)
path.addLine(
to: .init(
x: self.currentPositionBottomRight.x,
y: self.currentPositionBottomRight.y
)
)
path.addLine(
to: .init(
x: self.currentPositionBottomLeft.x,
y: self.currentPositionBottomLeft.y
)
)
path.addLine(
to: .init(
x: self.currentPositionTopLeft.x,
y: self.currentPositionTopLeft.y
)
)
}
.stroke(Color.blue, lineWidth: CGFloat(1))
}
}
}
角落:
import SwiftUI
struct CropImageViewRectangleCorner: View {
@Binding var currentPosition: CGPoint
@Binding var newPosition: CGPoint
var displacementX: CGFloat
var displacementY: CGFloat
var body: some View {
Circle().foregroundColor(Color.blue).frame(width: 24, height: 24)
.offset(x: self.currentPosition.x, y: self.currentPosition.y)
.gesture(DragGesture()
.onChanged { value in
self.currentPosition = CGPoint(x: value.translation.width + self.newPosition.x, y: value.translation.height + self.newPosition.y)
}
.onEnded { value in
self.currentPosition = CGPoint(x: value.translation.width + self.newPosition.x, y: value.translation.height + self.newPosition.y)
self.newPosition = self.currentPosition
}
)
.opacity(0.5)
.position(CGPoint(x: 0, y: 0))
.onAppear() {
if self.displacementX > 0 || self.displacementY > 0 {
self.currentPosition = CGPoint(x: self.displacementX, y: self.displacementY)
self.newPosition = self.currentPosition
}
}
}
}
关于ios - 使用 SwiftUI 和 contentMode = .aspectFit 动态裁剪图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59211075/
我正在尝试将 UINavigationBar 的背景设为图像,但该图像并不是栏的确切大小。由于某种原因,我似乎无法正确设置栏的 contentMode 。这是我的代码: override func v
我正在尝试将我的 UITableView 设置为较小的高度并设置了 contentMode,但是,我无法让它滚动……它只是减小了尺寸。我做错了什么? [self.tableView setConte
所以我有这个 UIImageView ,上面有一个图像。当我使用普通的 iPhone 显示屏时,它在 UIImageView 内完全按照预期显示 - 在 UIImageView 范围内,问题是当我使用
我正在绘制一堆 UIImageView (100x100) 作为菜单项。每个都有自己的图像,有些大于 100x100,有些更小。默认情况下,具有较大图像的 imageView 会按比例缩小以很好地适应
let assests : PHAsset = self.asset[indexPath.item] as! PHAsset PHImageManager.defaultManager().r
我正在尝试将 UIImageView 的图像属性设置为我正在使用 CoreImage 进行模糊处理的图像。该代码与未过滤的图像完美配合,但是当我将背景图像设置为过滤后的图像时,contentMode
我完全被这个尺寸错误难住了。我的 View 布局中有一个 UIImageView 和一个 UITableView。 UIImageView 在 IB 中设置为 Aspect Fit,当我使用 IB 设
我有一个大小为 366 x 375 的 UIImageView(由 NSLog 语句确认)和一个大小为 400 的 UIImage x 600(再次通过日志语句确认)。我已尝试设置 contentMo
我正在使用 AlamofireImage,我注意到它具有设置所需图像的内容类型的功能。但是,我看不到设置占位符图像本身的内容类型的可能性。 例如,现在在我的 cellForRow 方法中我正在做: l
我有以下代码,适用于旧版 IOS 应用程序,但现在在 xcode 9 中不再适用: 我得到的错误是: 'ContentMode' is not a member type of 'UIView' 代码
我正在使用 CIFilter 为图像添加滤镜。过滤图像后的结果图像大小如下:CGRectMake(10, 10, 70, 70)。我无法将生成的图像内容模式设置为 ScaleAspectFill。这是
我使用 [myButton setImage:forState:]; 为我的 UIButton 设置了一个 UIImage我使用 [[myButton imageView] setContentMod
在 Obj-C 中 imageView.contentMode = UIViewContentModeScaleAspectFill; 将设置 contentMode。 为什么 imageView.c
我对 UIImageView 显示图像的方式感到非常失望。 我有以下代码: UIImageView *imgview = [[UIImageView alloc] initWithFrame:CGRe
我有一个 Collection View 。我在 Collection View 的每个单元格上放置了一个 ImageView。然后我将 ImageView 的 contentMode 设置为 Sca
在照片框架中,我正在尝试查看使用 PHImageManager 中的 RequestImageFor Asset 方法的教程。 这是一段代码: let asset:PHAsset = self
我很难理解 UIViewContentModeScaleAspectFit 的工作原理。我正在开发应用程序,我希望图像应该以图像周围必须有空白区域的方式重新绘制,并且图像必须设置在 ImageView
当我将图像(通过 Storyboard )添加到按钮图像内容模式时不起作用。当我通过图像插入和另一台设备(iPad)上的标题插入修复它(iPhone)时,它失去预期比率?我该如何修复它?? 最佳答案
我正在尝试创建一个小示例来解释 UIImageView 的 contentMode (scaleAspectFill)。 一切都是编码的,没有使用 Storyboard。检查了很多有助于解释这一点的例
我一直在关注 Ray Wenderlics 关于如何创建基本绘图应用程序的教程。 除了在 uiimageview 上绘制内容模式更改时,我让它工作得很好。 我在 Storyboard 中将它设置为 a
我是一名优秀的程序员,十分优秀!