SwiftUI Parent Height - swiftui

In SwiftUI how can I give a parent view height 0 and hide all the children (because parent height is 0). This code still shows ZStack. It is taking height from the children.
ZStack {
RoundedRectangle(cornerRadius: 10.0, style: /*#START_MENU_TOKEN#*/.continuous/*#END_MENU_TOKEN#*/)
.fill(Color.red)
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.white)
}
.frame(maxHeight: 0)
.animation(.spring())

You need just clip after setting frame, because any stack is just transparent container and applied frame is really 0 height, but content is visible through it, so the solution is
ZStack {
RoundedRectangle(cornerRadius: 10.0, style: /*#START_MENU_TOKEN#*/.continuous/*#END_MENU_TOKEN#*/)
.fill(Color.red)
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.white)
}
.frame(maxHeight: 0)
.clipped() // << here !!
.animation(.spring())

Related

Two different transitions in a ZStack

I am new to SwiftUI and trying to play around with some stuff.
I want to have a ZStack so I can have a background color with a see through black color that should animate on the opacity. On top of that I want to animate a "card view" in from the bottom. This is not possible currently with the code I have managed to use. Both background color and the card view is animating on the opacity - from invisible to visible.
How do I animate these two items inside the ZStack with a different transition?
Here is what I have done so far but without the correct result:
ZStack {
Color.black
.ignoresSafeArea()
.opacity(animateSmileys ? 0.3 : 0)
.animation(.easeInOut)
.zIndex(0)
VStack {
Spacer()
VStack(spacing: 30) {
Text("Hvordan har du det i dag?")
.font(.title2)
.fontWeight(.heavy)
.foregroundColor(Color("playerTopView"))
HStack {
ForEach(Array(moods.enumerated()), id: \.offset) { index, mood in
SmileyView(bgColor: mood.bgColor, smileyName: mood.smileyName)
.aspectRatio(contentMode: .fit)
.scaleEffect(CGFloat(animateSmileys ? 1 : 0), anchor: .center)
.rotationEffect(.degrees(animateSmileys ? 0 : 180), anchor: .center)
.animation(.interpolatingSpring(stiffness: 150, damping: 10).speed(2).delay(Double(index) * 0.2), value: animateSmileys)
}
}
HStack {
Spacer()
}
}
.padding()
.padding(.top, 20)
.background(Color("backgroundColor"))
.clipShape(RoundedRectangle(cornerRadius: 30, style: .continuous))
.shadow(radius: 20)
}
.padding()
.transition(.move(edge: .bottom))
.animation(.spring())
.onAppear {
animateSmileys = true
}
.zIndex(1)
}
Hope you guys can help me!
I tried the above code and moving the .transition(.move(edge: .bottom)) and .animation(.spring()) from the VStack holding the "card view" to the VStack inside the VStack.

SwiftUI: add border to view without bleeding out?

I have a simple view like this:
struct TestView: View {
var body: some View {
Button(action: {}) {
Text("Button")
.padding()
.foregroundColor(.white)
}
.background(Color(.gray))
// .cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(.red, lineWidth:4)
)
}
}
It draws this:
I am trying to understand why the border bleeds out of the view (gray area). I want to draw the border so it stays inside the view (in the gray area). It looks like half of its width is out and Half in.
How can I make the border stay inside the overlay bounds?
How can I make the border stay inside the overlay bounds?
Use strokeBorder(_:lineWidth:antialiased:) instead — this draws an inner stroke.
Button(action: {}) {
Text("Button")
.padding()
.foregroundColor(.white)
}
.background(Color(.gray))
.overlay(
RoundedRectangle(cornerRadius: 10)
.strokeBorder(.red, lineWidth: 4) /// here!
)
If you want it to look like this:
Button(action: {}) {
Text("Button")
.padding()
.foregroundColor(.white)
}
.background(Color(.gray))
.clipShape(RoundedRectangle(cornerRadius:10))
.overlay(
RoundedRectangle(cornerRadius: 10)
.strokeBorder(.red, lineWidth: 4) /// here!
)

How to detect whether the scrollview was scrolled or not in SwiftUI?

I have a horizontal ScrollView and would like to provide a function that when the first element is not visible anymore an arrow should appear to signalize that there are some other elements.
I've tried the DragGesture() to read the translation.width but it seems to be buggy in combination with the ScrollView.
So I'm looking for a way to detect whether the ScrollView was scrolled and how far. Is there any way?
private let gridItems = [GridItem(.flexible())]
ScrollView(.horizontal, showsIndicators: false) {
HStack{
LazyHGrid(rows: gridItems){
ForEach(viewModel.imageOptions, id: \.self){ image in
ZStack {
Image(image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.background(Color.white)
.clipShape(Circle())
.background(
Circle()
.clipShape(Circle())
.shadow(color: Color.black.opacity(0.4), radius: 3, x: 5.0, y: 5.0)
)
.onTapGesture {
print("selected")
}
.padding(15)
Circle()
.strokeBorder(Color.orange, lineWidth: 5)
.frame(width: 70, height: 70)
}
}
}
}
}
}

Dynamic height for TextEditor

I'm trying to fit the TextEditor inside a ScrollView.
Is there a way to make TextEditor only takes up the space that it needs to fit all text?
or simply, how to change the height of the TextEditor dynamically to fit all the text?
You can put it in a ZStack with an invisible Text for sizing:
ZStack {
TextEditor(text: $text)
Text(text).opacity(0).padding(.all, 8) // <- This will solve the issue if it is in the same ZStack
}
using
TextEditor(text: someTextBinding)
.fixedSize(horizontal: false, vertical: true)
does the job for me (== height is dynamic, width is static)
Dynamic height can also be achieved with combination use of Text and overlay() with TextEditor.
Text(textVal.isEmpty ? "Your placeholder" : textVal)
.font(.body)
.padding(.vertical, 8)
.padding(.horizontal, 18)
.foregroundColor(Color.gray)
.opacity(textVal.isEmpty ? 1 : 0)
.frame(maxWidth: .infinity, minHeight: 40, alignment: .leading)
.background(
RoundedRectangle(cornerRadius: 5)
.stroke(Color.gray.opacity(0.2), lineWidth: 1)
.padding(.horizontal, 15)
)
.overlay(
TextEditor(text: $textVal)
.font(.body)
.foregroundColor(Color.black)
.multilineTextAlignment(.leading)
.padding(.horizontal, 15)
)
For transparent background of TextEditor add below code on View init:
init(yourProperty: String) {
self.yourProperty = yourProperty
UITextView.appearance().backgroundColor = .clear
}

how to strech image on one side in swiftUI, like a .9 file in Android?

i have an image that i want to strech only it's height to fit different content, how do i do that in swiftUI? right now it looks like this
struct ContentView: View {
var body: some View {
VStack {
HStack {
VStack(alignment: .leading, spacing: 130) {
Text("Title")
.font(.headline)
.foregroundColor(.primary)
Text("text")
.font(.subheadline)
.foregroundColor(.secondary)
Text("padding")
}
.padding(.vertical)
Spacer()
Image("rightTag")
.resizable(capInsets: .init(top: 0, leading: 0, bottom: 0, trailing: 0), resizingMode: .stretch)
.aspectRatio(contentMode: .fit)
.frame(maxWidth: 20)
}
.frame(maxWidth: screen.width - 60)
.padding(.leading)
.background(.white)
.cornerRadius(20)
}
}
}
how can i stretch its height to fit this outer frame? ragular resizable and stuff can't get it done.
any helped would be wonderful! Thanks!
sry i didn't make myself clear earllier.
Here is possible approach. However as I see now you'd rather need to stretch not the entire original image, but only middle of it, so in real project it would be needed to make your image tri-part and apply below stretching approach only to middle (square) part.
Approach uses asynchronous state update, so works in Live Preview / Simulator / RealDevice. (Tested with Xcode 11.2 / iOS 13.2)
struct ContentView: View {
#State private var textHeigh: CGFloat = .zero
var body: some View {
VStack {
HStack(alignment: .top) {
VStack(alignment: .leading, spacing: 130) {
Text("Title")
.font(.headline)
.foregroundColor(.primary)
Text("text")
.font(.subheadline)
.foregroundColor(.secondary)
Text("padding")
}
.padding(.vertical)
.alignmentGuide(.top, computeValue: { d in
DispatchQueue.main.async {
self.textHeigh = d.height // !! detectable height of left side text
}
return d[.top]
})
Spacer()
Image("rightTag")
.resizable()
.frame(maxWidth: 20, maxHeight: max(60, textHeigh)) // 60 just for default
}
.frame(maxWidth: screen.width - 60)
.padding(.leading)
.background(Color.white)
}
}
}