SwiftUI fill shape with a custom pattern - swiftui

I would like to use .fill modifier to fill a Shape with a pattern, for example, a checked pattern.
I have for example
Rectangle()
.fill(Color.red)
I know I can use something like
let myGradient = LinearGradient(gradient: Gradient(colors: [.black, . red]), startPoint: .top, endPoint: .bottom)
.fill(myGradient)
But I cannot get any of the gradients to create the pattern I am after
I see that fill needs to conform to ShapeStyle, is there an example of how I could create my own ShapeStyle
I do not want to create a custom shape only a custom fill

Related

SwiftUI Why do these RoundedRectangles not take up all the space in my ScrollView

struct Test: View {
var body: some View {
ScrollView{
RoundedRectangle(cornerRadius: 5)
.fill(.red)
RoundedRectangle(cornerRadius: 5)
.fill(.red)
Text("test")
}
}
}
So I have this view, and from what I know RoundedRectangles are supposed to be flexible and take up all the space so how come when I put two in a ScrollView like this they seem to take the minimum possible space?
The scroll view sets its content size based on the size of its children. The shapes try to fill their parent. Both are trying to figure out how big to be.
Your going to need to put them in a different container that has a fixed size.

how can i replicate this background texture and color style in SwiftUI?

This is my example code of my app. I want my background to be like this image with soft pink transition to soft blue with some texture soft blur on top of it.
how may i replicate this with just swiftui?
So the first thing you're going to want to do is to utilize LinearGradient and RadialGradient which are the two types of gradients that you can use to compose several layers. There are other ways you can do it by using .background or .overlay modifiers however in my example I want to keep it as simple as possible and allow you the freedom to explore other options with it. I've created two extensions so that you can simply reference LinearGradient.blueClearGradient, for example, directly anywhere in your app. NOTE:: I used different colors, feel free to use what you want to use for your colors. I did this to make it more visually apparent what the individual pieces of the view were composed of.
extension LinearGradient {
static let blueClearGradient = LinearGradient(colors: [.blue, .clear],
startPoint: .bottom,
endPoint: .top)
}
extension RadialGradient {
static let radialYellowGradient = RadialGradient(colors: [.yellow, .clear],
center: .topLeading,
startRadius: 100,
endRadius: 400)
static let radialRedGradient = RadialGradient(colors: [.red, .clear],
center: .topTrailing,
startRadius: 100,
endRadius: 400)
}
Once you have those extensions it's as simple as utilizing them the same as you would any other view. You can use them to .fill or even as a straight up view themselves. In this example, I used them as a .fill for a shape.
struct GradientExample: View {
var body: some View {
ZStack {
Rectangle()
.fill(RadialGradient.radialRedGradient)
Rectangle()
.fill(RadialGradient.radialYellowGradient)
Rectangle()
.fill(LinearGradient.blueClearGradient)
}
}
}
Doing it this way produces a view that might look something like this.

Project ARKit + SwiftUI + Different layout preview/simulator

I cannot understand why in the simulator the layout is different from the layout displayed in xcode/preview.
struct ContentView : View {
var body: some View {
ZStack(alignment: .bottom) {
ARViewContainer()
Text("hello")
}
}
}
here the screenshots:
TLDR; I don't know why your simulator and preview don't match, but I do know why it's appearing the way that it is on the device. Are you getting any errors in the debug?
Any container views in SwiftUI will only take up the required space that they need. they will also distribute according to your settings. For example, you have a ZStack that contains a bottom alignment. You also have a ARViewContainter() that takes up a portion of that stack. They are aligned behind each other on the Z axis where the text is in front and the other container is behind. A quick way to prove this and test it is to include a background shape behind everything for example.
var body: some View {
ZStack {
Rectangle().edgesIgnoringSafeArea(.all)
.foregroundColor(Color.red)
//Your Views
}
}
This will force the ZStack to take up all available space and your other views should then align as expected. Basically, your Text is aligning to the bottom of the maximum provided space, which is being provided by your ARViewContainer()
Further Reading and Understanding
Views only take up the space required for what's in them, unless otherwise specified.
ZStacks operate on the Z axis, forward/backwards.
In your case you have a view with a set size called ARViewContainer() which takes up the width of the screen and a portion of the height. Since it's the largest view you have, the ZStack inherits that size.
Your text is smaller than the ZStack so the ZStack does NOT inherit the size. You do however have a .bottom assignment. So your text is over your ARViewContainer() and aligned to the .bottom edge of that container.
Finally the ZStack is centered in the remaining space available, giving it the impression that your .bottom isn't doing anything, when in reality it is.
Reproducing the Issue
Here is a code snippet that reproduces your issue and makes it a bit clearer and easier to understand.
var body: some View {
ZStack(alignment: .bottom) {
Rectangle().foregroundColor(Color.yellow).frame(width: 100, height: 100, alignment: .center)
Text("Test")
}
}

SwiftUI - set the centre of a text view to be in an absolutely fixed position at all times

I am attempting to build a soccer app. My main detail view shows match statistics. I cannot find any way to get the central text element showing the score of the match to stay in the absolute center, so that the colon in the text is perfectly centred over the guideline on the middle of the screen. With different numbers either side of the colon, it gets shifted slightly out of place.
Is there any way to fix this element to be exactly centered under any circumstances? I have attached a screenshot showing the misalignment.
Code:
VStack() {
HStack(alignment: .center) {
Text("\(matchItem.HomeGoals) : \(matchItem.AwayGoals)")
.font(.system(size: 35.0))
.fontWeight(.heavy)
.foregroundColor(Color.white)
.lineLimit(3)
.multilineTextAlignment(.center)
.fixedSize(horizontal: true, vertical: true)
.allowsTightening(false)
}.padding(15)
}.frame(width: 75, height: 80, alignment: .center)
Example:
You can put your View in a ZStack and the ":" on another Z-level, so it no longer depends on other elements in the same horizontal stack.

Update UIViewRepresentable size from UIKit in SwiftUI

I'm embedding a view controller with variable-height UITextView inside a parent SwiftUI VStack and the view controller sizes it's frame to the whole screen between viewDidLoad and viewDidLayoutSubviews. The UITextView expands only to the size of the text inside itself and centers itself inside the parent view.
I'm trying to add this view controller in a VStack and have it behave externally like other SwiftUI components do - sized exactly to the content it contains - but it wants to be sized to the whole screen minus the other VStack elements.
I can get the correct size of the UITextView in didLayoutSubviews and pass it upwards to SwiftUI where it can be set properly - but where do I do that?
In the example screenshot below, the orange is the embedded UIView background, the green is the UITextView and the VStack looks like this:
VStack {
HighligherVC()
Text("Tap and drag to highlight")
.foregroundColor(.gray)
.font(.caption)
}
Without being able to see more of your code, it's slightly difficult to say what the best solution would be, but based purely on this part of your question...
I can get the correct size of the UITextView in didLayoutSubviews and pass it upwards to SwiftUI where it can be set properly - but where do I do that?
I would suggest that you pass a binding property to your view controller that can be set to the calculated text view height, meaning that the view that contains your VStack would have a #State property like this:
#State private var textViewHeight: CGFloat = 0
You would then declare a #Binding property on your HighlighterVC and add an initializer like this:
#Binding var textViewHeight: CGFloat
init(textViewHeight: Binding<CGFloat>) {
self._textViewHeight = textViewHeight
}
And then you would set textViewHeight to the calculated height in your didLayoutSubviews and add a .frame modifier to your HighlighterVC like this:
VStack {
HighlighterVC(textViewHeight: self.$textViewHeight)
.frame(height: self.textViewHeight)
Text("Tap and drag to highlight")
.foregroundColor(.gray)
.font(.caption)
}
Like I said at the beginning of my answer, this solution (that I believe would work, but since I can't test it, I'm not 100% certain) is based on your thoughts about what it is that you need. Without seeing more code, it's impossible for me to say if this is the best solution.
Add fixedSize may solve this.
.fixedSize(horizontal: false, vertical: true)