I am applying rotation gesture and magnify gesture in a ZStack. But the ZStack is not getting rotated , but the image inside the ZStack is getting rotated and scaled upon the gesture while I did applied the rotation and scale on ZStack.
Here is My Code :
var body: some View {
NavigationView {
VStack {
GeometryReader { geo in
let w = geo.size.width
let h = geo.size.height
let size = getSize(h, w)
if size.width > 0 && size.height > 0 {
ZStack {
Image(uiImage: service.backgroundImage!)
.resizable()
.scaledToFill()
.frame(width: size.width, height: size.height, alignment: .center)
.clipped()
//This is the ZStack --------------------
ZStack{
Image(uiImage: foregroundImage)
.resizable()
.scaledToFit()
.background(GeometryGetter(rect: $imageRect))
}
.rotationEffect(rotationAngle)
.scaleEffect(scale)
.gesture(DragGesture(minimumDistance: 0 , coordinateSpace: .local)
.onChanged { value in
self.offset.x += value.location.x - value.startLocation.x
self.offset.y += value.location.y - value.startLocation.y
print("->> Location - \(value.location)")
})
.offset(x: offset.x, y: offset.y)
.gesture(simultaneous)
.background(.blue)
}
.frame(width: size.width, height: size.height, alignment: .center)
.clipped()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(AppDefaults.Theme.secondaryColor)
}
}
bottomContainerView()
}
.background(Color.black.ignoresSafeArea())
}
}
Add .background(.blue) before .rotationEffect(rotationAngle).
view modifier order matters in swiftUI.
take a look here
Related
How can I hide my arrow text after ScrollView has scrolled?
struct Skroll: View {
var body: some View {
VStack(alignment: .trailing) {
Text("<-")
.font(.system(size: 25).bold())
.kerning(-3)
ScrollView(.horizontal, showsIndicators: false) {
HStack {
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
}
}
}
.padding()
}
}
I can't figure out how can I hide text after scrolling, I'm new and just learning SwiftUI
Looks like what you need is to get the current position of the scroll view. See here on how to do that. Then you can choose to display Text("<-") based on a flag which is modified when ScollView reaches a certain point
if !hideText {
Text("<-")
.font(.system(size: 25).bold())
.kerning(-3)
}
It might be also possible that you might achieve the same result by moving your Text("<-") inside the scroll view. See if below works for you
ScrollView(.horizontal, showsIndicators: false) {
Text("<-")
.font(.system(size: 25).bold())
.kerning(-3)
HStack {
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
}
}
I think I figured out how to do it
struct Skroll: View {
#State var scrollViewOffset: CGFloat = 0
#State var start: CGFloat = 0
var body: some View {
VStack(alignment: .trailing) {
HStack {
Image(systemName: "arrowtriangle.right.fill")
.font(.system(size: 35).bold())
.opacity(-scrollViewOffset > 160.0 ? 1 : 0)
.animation(.easeOut, value: scrollViewOffset)
Spacer()
Image(systemName: "arrowtriangle.left.fill")
.font(.system(size: 35))
.opacity(-scrollViewOffset > 160.0 ? 0 : 1)
.animation(.easeOut, value: scrollViewOffset)
}
ScrollView(.horizontal, showsIndicators: false) {
HStack {
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
Rectangle()
.frame(width: 200, height: 300)
.cornerRadius(20)
}
.overlay(GeometryReader { proxy -> Color in
DispatchQueue.main.async {
if start == 0 {
self.start = proxy.frame(in: .global).minX
}
let offset = proxy.frame(in: .global).minX
self.scrollViewOffset = offset - start
print(self.scrollViewOffset)
}
return Color.clear
})
}
}
.padding()
}
}
result
I replaced my text with an image. I'm not sure if this is the right solution and I don't know if it might cause any errors, but this works for me. Maybe someone will find it useful too
A whiteness is seen in the area drawn with the red line. If I change the background color of the most inclusive Vstack, that white area changes.
Deleting spacer() lines doesn't work.
Why is there a gap even though there is no space in between?
struct TabbarView: View {
var body: some View {
VStack{
Spacer()
ZStack{
Color.orange.opacity(0.5)
VStack(spacing: 0){
Text("Home")
.padding()
}
}
Spacer()
HStack{
VStack{
Image(systemName: "homekit")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.size.width / 15, height: UIScreen.main.bounds.size.height / 25)
}
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 13)
.background(Color.purple)
}
.ignoresSafeArea()
// .background(Color.purple.shadow(radius: 2))
}
}
enter image description here
you can add for VStack:
VStack {}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
updated:
struct ContentView: View {
var body: some View {
ZStack {
Color.orange.opacity(0.5)
VStack {
Spacer()
VStack(spacing: 0){
Text("Home")
.padding()
}
Spacer()
HStack {
VStack {
Image(systemName: "homekit")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 25, height: 25, alignment: .center)
.frame(width: UIScreen.main.bounds.size.width / 15, height: UIScreen.main.bounds.size.height / 25)
}
}
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 13)
.background(Color.purple)
}
}
.ignoresSafeArea()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
you used nesting incorrectly and there is a native TabView for tabs
result:
Here , I'm trying to apply same rotation in both these elements.But these object or elements are doing un wanted behaviour, they are not rotating as same as others . So I want to rotate them all as same , So that no the blue card gets behind the image.
I mean I want them all to be in same rotation.
Here my code -
var body: some View {
VStack(spacing : 10){
ZStack {
ZStack (alignment : .bottom){
ZStack(alignment : .bottom){
Image("cat")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: length, height: length)
Text("<>")
.frame(width: 20, height: 20)
.padding()
.background(Color.orange)
.cornerRadius(15)
}
.frame(width: length, height: length)
.background(.blue)
.rotationEffect(Angle(degrees: Double(-totalRotation.width)))
Text("<>")
.frame(width: 20, height: 20)
.padding()
.background(Color.orange)
.cornerRadius(15)
.gesture(
DragGesture()
.onChanged { value in
totalRotation.width = value.translation.width + currentRotation.width
}
.onEnded { value in
currentRotation = totalRotation
mainAngle = totalRotation
}
)
Text("\(mainAngle.width) --- \(totalRotation.width)")
.foregroundColor(.white)
}
.frame(width: length, height: length)
.background(.blue)
.rotationEffect(Angle(degrees: Double(-mainAngle.width)))
}
.frame(width: length, height: length)
.rotationEffect(Angle(degrees: Double(-mainAngle.width)))
}
.frame(width: length, height: length)
Text("\(angle)")
}
}[![Here the image to get much information][1]][1]
I’m having problems with my app with different screen sizes. I made a little example to show the problem.
I have a screen with a text and a button on the left and an image on the right. Behind this, in zstack, I have the same image bigger and a layer over this image with opacity 0.5.
The problem is that I’m using measures relative to the screen and the result is different. In the image attached you can see the differences.
This is the code.
struct Screen2: View {
var body: some View {
VStack {
ZStack {
ZStack {
Image(uiImage: resizeImage(image: UIImage.init(named: "cover.jpeg")!, targetSize: .init(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.width)))
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9, alignment: .center)
.cornerRadius(0)
Color.black
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9, alignment: .center)
.opacity(0.5)
}
.edgesIgnoringSafeArea(.all)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 5, alignment: .top)
HStack(alignment: .top) {
VStack {
Text("The Suicide Squad")
.font(.title)
.shadow(color: .white, radius: 5)
Button("Publish") {
print("Published")
}
.background(Color.blue)
.foregroundColor(.white)
.padding()
}
.padding([.leading], 10)
Spacer()
Image(uiImage: resizeImage(image: UIImage.init(named: "cover.jpeg")!, targetSize: CGSize.init(width: UIScreen.main.bounds.width / 4, height: UIScreen.main.bounds.height / 4)))
}
}
HStack {
Spacer()
Text("TESTING")
Spacer()
}
.background(Color.red)
Spacer()
}
}
func resizeImage(image: UIImage, targetSize: CGSize) -> UIImage {
let size = image.size
let widthRatio = targetSize.width / size.width
let heightRatio = targetSize.height / size.height
var newSize:CGSize
if (widthRatio > heightRatio)
{
newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)
}
else
{
newSize = CGSize(width: size.width * widthRatio, height: size.height * widthRatio)
}
let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)
image.draw(in: rect)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
}
Anyone can help me to show the result in the same way in every screen size?
Thank you
You're resizing your cover to one targetSize, and then setting an other size using .frame, and then adding one more frame to container ZStack. Why would you do that?
When image frame is changed and contentMode set to .fill, it's gonna be centered in its frame but rest of the image will be visible out of the frame. You can see this in this example:
let targetSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9)
Image("cover")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(0)
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
.overlay(Rectangle().stroke(lineWidth: 5).foregroundColor(.red))
This can be fixed with .clipped() modifier. It's same as clipsToBounds on UIKit if you're familiar with that
When you're applying edgesIgnoringSafeArea to one item in VStack, it works like offset modifier, which means that next item won't be right after. You need to apply edgesIgnoringSafeArea to whole VStack, and, if needed, you can than disable if .edgesIgnoringSafeArea([]) for items that needs safe area inset
There's no need to resize images before passing it to Image, especially you don't want to do that inside view builder function, because this gonna be re-calculated each time you update this view. Usually applying needed modifiers is totally enough to get needed result, let SwiftUI optimize it for your:
VStack(spacing: 0) {
ZStack(alignment: .bottom) {
let targetSize = CGSize(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height / 2.9)
ZStack {
Image("cover")
.resizable()
.aspectRatio(contentMode: .fill)
.cornerRadius(0)
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
.clipped()
Color.black
.opacity(0.5)
}
.frame(width: targetSize.width, height: targetSize.height, alignment: .center)
HStack(alignment: .top) {
VStack {
Text("The Suicide Squad")
.font(.title)
.shadow(color: .white, radius: 5)
Button("Publish") {
print("Published")
}
.background(Color.blue)
.foregroundColor(.white)
.padding()
}
.padding([.leading], 10)
Spacer()
Image("cover")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: UIScreen.main.bounds.width / 4)
}
.edgesIgnoringSafeArea([])
}
HStack {
Spacer()
Text("TESTING")
Spacer()
}
.background(Color.red)
Spacer()
}
.edgesIgnoringSafeArea(.all)
Result:
My code:
public var body: some View {
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
Text("Text")
.padding(.bottom, 42)
.foregroundColor(.red)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.background(Color.red)
}
makes ZStack takes almost all screen height. But I expect it will take height from .frame() method.
I have a workaround for you, it's a bit messed up but works
public var body: some View {
ZStack {
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.zIndex(0)
ZStack {
VStack {
VStack {
Text("Text")
.padding(.top, 42)
.foregroundColor(.red)
}
.frame(width: UIScreen.main.bounds.width, height: 182)
VStack {
Text("Your texts here")
}
.frame(width: UIScreen.main.bounds.width)
Spacer()
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
.zIndex(1)
}
.background(Color.red)
}
I simply made your ellipse on another layer and text on the other.
ZStack(alignment: .bottom) {
Ellipse()
.fill(.yellow)
}
.frame(width: 546, height: 364)
.position(x: UIScreen.main.bounds.size.width / 2, y: Spacing.padding_0_5)
.edgesIgnoringSafeArea(.top)
.zIndex(0)
The .zIndex(0) makes sure that the view is in the background.
ZStack {
VStack { // This VStack contains all your text
VStack { // First VStack
Text("Text")
.padding(.top, 42)
.foregroundColor(.red)
}
.frame(width: UIScreen.main.bounds.width, height: 182)
VStack { //Second VStack
Text("Your texts here")
}
.frame(width: UIScreen.main.bounds.width)
Spacer()
}
.frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
}
.zIndex(1)
Here, the ZStack takes up the entire screen. We added a VStack which contains your texts.
The first VStack has your main label over the Ellipse, and its frame is hardcoded according to the height of the Ellipse (1/2 the height as the other half of the ellipse is outside the screen).
The second VStack starts from the end of our first VStack which was the functionality needed, finally added a spacer() so that the text is placed at the top rather than middle.
The zIndex(1) makes sure that is placed over the elements at zIndex(0)