UIScrollView always snaps back to center - uiscrollview

I have I vertical ScrollView in SwiftUI when I add "normal" Components then I can scroll normal but when I add a Component which gets the data from a websocket only the Content in the middle it is scrollable and the Content at the top and the bottom always snaps back to the middle
struct HomeView : View {
#EnvironmentObject var socketData: Socket
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack {
Text(String(socketData.message))
LiveStats()
LiveStats()
LiveStats()
LiveStats()
LiveStats()
Weather() //This is the View which gets the data async
}
}
}
}

I fixed the problem by applying a frame to the Weather struct but I don't know how to fix the problem when I don't have a certain height.

Related

Animate a button's text and position at the same time in SwiftUI

I have a very simple view that only shows a Text, a Shape, and a Button stacked vertically in a ScrollView. The Shape is a Capsule and is conditionally shown only when showCapsule is true.
struct ContentView: View {
#State var showCapsule = true
var body: some View {
ScrollView {
VStack(spacing: 16) {
Text("Why, oh why? 😩")
.font(.headline)
if showCapsule {
Capsule()
.frame(maxWidth: .infinity)
.frame(height: 100)
.foregroundColor(.blue)
}
Button {
showCapsule.toggle()
} label: {
Text(showCapsule ? "Hide" : "Show")
}
.buttonStyle(.bordered)
}
.frame(maxWidth: .infinity)
.padding()
}
.animation(.default, value: showCapsule)
}
}
Observed and expected animation
I want to animate the appearance and disappearance of the Capsule, but the result is totally not what I want. While the Capsule fades out (which is okay), the button is animated in two different ways simultaneously:
Its background shape (the grey rounded rectangle) move from the old to its new position.
Its text fades out at its old position and fades in at its new position.
Of course, (2) is not what I want. Instead, I want the button to move as a unit: The entire thing should move from its old to its new position while the text is faded inside of it.
The broader picture
This is a minimal example for a broader question: How do I animate changes to a view that is semantically the same but value-wise different?
In the Button initializer, I use a ternary operator to conditionally pass a different string to its Text label:
Button {
showCapsule.toggle()
} label: {
Text(showCapsule ? "Hide" : "Show")
}
Text("Hide") is a different value than Text("Show"), so I guess that's why SwiftUI can't identify them and doesn't "understand" that it should animate them in place. I observed the same behavior with custom views with let constants. Is there a way to make SwiftUI treat such views – and especially this Button – as a unit and animate them correctly?
Note
I'm not looking for a workaround like using two Text fields (or Buttons) and show/hide them by setting their opacity accordingly. Rather looking for a general solution for this kind of problem that solves the identity problem rather than patching its symptoms.
You can fix this by adding .drawingGroup modifier to your button:
Button(showCapsule ? "Hide" : "Show") {
showCapsule.toggle()
}
.drawingGroup()
.buttonStyle(.bordered)
Alternatively, you could have two buttons that are shown and hidden:
ZStack {
Button("Hide") {
showCapsule.toggle()
}
.buttonStyle(.bordered)
.opacity(showCapsule ? 1 : 0)
Button("Show in a very long button") {
showCapsule.toggle()
}
.buttonStyle(.bordered)
.opacity(showCapsule ? 0 : 1)
}

Image resizing makes Button unclickable

I have a simple scrollview with a SDWebImage pulling in Firebase URL links to display images. For some bizarre reason, when I do not give a specific frame to my images, I can click on the button positioned in the bottom left corner. But when I give it a max height or any height at all, the button becomes unclickable. This seriously might be the weirdest SwiftUI issue I have ever seen - any help would be great.
import SwiftUI
import SDWebImageSwiftUI
struct Test2FeedView: View {
#StateObject var viewmodel = FeedViewModel()
#State var show : Bool = false
var body: some View {
ScrollView{
VStack(spacing:5) {
ForEach(viewmodel.posts){ post in
ZStack(alignment:.bottomLeading) {
WebImage(url: URL(string: post.original_posted_image))
.resizable()
.scaledToFill()
.frame(maxHeight:440)
.clipped()
Button(action: {
show.toggle()
}){
Text("PRESS ME")
}
}
}
}
}.sheet(isPresented: $show) {
Text("hey")
}
}
}
The Button becomes unclickable because the result of .clipped() is only visual — in reality, the image spans all the way 'above' the button, thus is being used for hit testing. You should use .allowsHitTesting(false) to disable that.
WebImage(url: URL(string: post.original_posted_image))
.resizable()
.scaledToFill()
.frame(maxHeight:440)
.clipped()
.allowsHitTesting(false) // <- here
try putting the .frame(maxHeight:440) just before .scaledToFill(), works for me.

How to add a focus ring to TextEditor in SwiftUI for MacOS

In contrast to TextField which has an animated blue focus ring, the TextEditor control doesn't have it. How can this be added? It should look and behave (i.e. animations) exactly like the one from TextField, so just adding a border isn't enough.
By using something like Introspect, you could do:
struct TextEditorWithFocusRing: View {
#Binding var text: String
var body: some View {
TextEditor(text: $text)
.introspectTextView { textView in
textView.enclosingScrollView?.focusRingType = .exterior
}
}
}
}

How do I indicate to swiftUI ScrollView that content size has changed?

I am writing a swiftUI app for macOS.
Consider this situation: I have a scroll view containing an image that is resizable. If I resize the window to smaller than the image, the scroll views bars appear as expected. If I use .scaleEffect(someStateVar) to resize the image (by changing someStateVar), the scroll view content does not update to the new size of the image.
Other than wrapping NSScrollView into a swiftUI view, how do I indicate to the swiftUI scrollview that the content size has changed?
Example that shows scaling the image does not set the "content size" of the scrollview. When you size the clock to large than the scroll view, the scroll bars do not appear and you cannot scroll. When you try to scroll, you briefly see the hidden areas but the view jumps back to the original location.
import SwiftUI
struct MyImageView: View {
#State var scale: CGFloat = 1
var theImage: some View{
ScrollView([.horizontal, .vertical]){
VStack{
HStack{
Image(systemName: "clock.fill")
.scaleEffect(scale)
}
}
}
}
var body: some View {
theImage
Slider(value: $scale, in: 1...1000)
}
}
struct ContentView: View {
var body: some View {
MyImageView()
}
}
You can use the .frame modifier to explicitly set the size of the VStack. The downside is that you have to know the full dimensions.
var theImage: some View{
ScrollView([.horizontal, .vertical]){
VStack{
HStack{
Image(systemName: "clock.fill")
.scaleEffect(scale)
}
}
.frame(width: 50 * scale, height: 50 * scale, alignment: .center)
}
}

In SwiftUI how do I put the tabs in a TabbedView at the top of the view?

I have a view with tabs on the bottom, one of the views has subviews, to separate the logic visually, I put the tabs of the subview at the top of the view with the following code and it works perfectly:
self.tabbar.frame = CGRect( x: 0,
y: view.safeAreaInsets.top,
width: self.view.frame.size.width,
height: 50)
How do I do this in SwiftUI?
In order to do this you could create your tabs view as a container of the individual tabs something like this...
struct TabbedView: View {
#State private var selectedTab: Int = 0
var body: some View {
VStack {
Picker("", selection: $selectedTab) {
Text("First").tag(0)
Text("Second").tag(1)
Text("Third").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
switch(selectedTab) {
case 0: FirstTabView()
case 1: SecondTabView()
case 2: ThirdTabView()
}
}
}
}
Doing this, you are conditionally populating the "Tab page" based on the value of the segmented control.
By using #State and $selectedTab the segmented control will update the selectedTab value and then re-render the view which will replace the page based on the new value of selectedTab.
Edit
Switches now work in SwiftUI beta. 👍🏻

Resources