Divide Rectangle with slanted divider with different views on each side? - swiftui

I am trying to split a rectangle into two sides with a slanted divider with background web images like this:
I tried using a triangle but having trouble dividing it in the correct direction and angle. Below is my working code I'm trying:
struct ContentView: View {
var body: some View {
VStack {
VStack {
Text("VS")
.bold()
.padding(4)
.background(.thinMaterial.opacity(0.8))
.clipShape(Circle())
}
.frame(maxWidth: .infinity, minHeight: 100)
.padding()
.background(
AsyncImage(url: URL(string: "https://picsum.photos/id/1037/1600/400"), transaction: Transaction(animation: .easeInOut)) { phase in
switch phase {
case .empty:
ProgressView()
case let .success(image):
image
.resizable()
.scaledToFill()
.frame(maxWidth: .infinity)
.transition(.opacity)
default:
Color.red
.transition(.opacity)
}
}
.overlay(
AsyncImage(url: URL(string: "https://picsum.photos/id/1041/1600/400"), transaction: Transaction(animation: .easeInOut)) { phase in
switch phase {
case .empty:
ProgressView()
case let .success(image):
image
.resizable()
.scaledToFill()
.frame(maxWidth: .infinity)
.transition(.opacity)
default:
Color.blue
.transition(.opacity)
}
}
.clipShape(Triangle())
)
)
.cornerRadius(4)
}
.padding()
}
}
struct Triangle: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
return path
}
}
This is what it looks like:
How can I accomplish the "back-slash" divider like in my first screenshot?

You just need to adjust the points in your Triangle to fit the shape that you desire. If you look at each point you currently have, you'll see that it matches the shape that it draws.
By adjusting a couple of the points, you can get the desired result:
struct Triangle: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.maxX * 0.33, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX * 0.66, y: rect.maxY))
return path
}
}

Related

I want to change the direction of the bar in a swiftui

I want to make a bar containing mutual data of two users. I want it to be like this image:
I also used the Rectangle() shape here. But the bar starts to fill up after 0.5, it seems empty before that. What should I do here?
The code I wrote is as follows:
HStack{
ZStack(alignment: .leading){
Rectangle()
.trim(from:0.1, to:0.6)
.fill(Color.init( red: 0.965, green: 0.224, blue: 0.49))
.frame(width: 55, height: 11)
Text(String(nowduelList.user1StepCount))
.font(.system(size: 8))
.bold()
.foregroundColor(Color.white)
}
ZStack(alignment: .trailing){
Rectangle()
.trim(from:0, to: 0.8)
.fill(Color.init( red: 0.208, green: 0.231, blue: 0.314))
.frame(width: 55, height: 11)
Text(String(nowduelList.user2StepCount))
.font(.system(size: 8))
.bold()
.foregroundColor(Color.white)
}
}
And this is an image of my View:
You can rotate the first view to achieve this:
HStack(spacing: -5) {
ZStack(alignment: .leading){
Rectangle()
.trim(from:0, to:0.8) // << Same as second view
.rotation(Angle(degrees: 180)) // << Rotation
.fill(Color.init( red: 0.965, green: 0.224, blue: 0.49))
.frame(width: 55, height: 11)
Text(String(951))
.font(.system(size: 8))
.bold()
.foregroundColor(Color.white)
}
ZStack(alignment: .trailing){
Rectangle()
.trim(from:0, to: 0.8)
.fill(Color.init( red: 0.208, green: 0.231, blue: 0.314))
.frame(width: 55, height: 11)
Text(String(231))
.font(.system(size: 8))
.bold()
.foregroundColor(Color.white)
}
}
Here is the full code you can modify and optimize the code as you want.
struct Triangle: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX/1.2, y: 0))
return path
}
}
struct LeadingTriangle: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.maxX/1.2-rect.maxX, y: 0))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: 0))
return path
}
}
var body: some View {
HStack{
ZStack(alignment: .leading){
Rectangle()
.fill(Color.white)
.frame(width: 150, height: 30)
.overlay(
Triangle()
.fill(Color.red)
)
Text(String(23.32))
.font(.system(size: 8))
.bold()
.foregroundColor(Color.white)
}
ZStack(alignment: .trailing){
Rectangle()
.fill(Color.white)
.frame(width: 150, height: 30)
.overlay(
LeadingTriangle()
.fill(Color.blue)
)
Text(String(23.32))
.font(.system(size: 8))
.bold()
.foregroundColor(Color.white)
}
}
}

SwiftUI inverted mask

I'm trying to create an view like in the screenshot with swiftui. The top frame should be light, other places should be dark.
SwiftUI add inverted mask
I tried to change it over the codes here, but I couldn't. how can i do it?
where I've come so far :
black color not show full screen and mask not working
func HoleShapeMask(in rect: CGRect) -> Path {
return
Path { path in
path.move(to: CGPoint(x: rect.minX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.minY))
}
}
struct ContentView: View {
#State var rect :CGRect = .zero
var body: some View {
GeometryReader{g in
Text("deneme")
.foregroundColor(.blue)
.frame(width: 124, height: 100, alignment: .center)
.background(Color.red)
.overlay(
GeometryReader { gp in
Color.clear.opacity(0.00001)
.onAppear(){
rect = gp.frame(in: .named("deneme"))
}
}
)
}
.coordinateSpace(name: "deneme")
.overlay(
Rectangle()
.fill(Color.black.opacity(0.8))
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.mask(HoleShapeMask(in: rect).fill(style: FillStyle(eoFill: true)))
)
}
}
my code screenshot :
i want to this screen :

How we can draw a stroke for a custom path in SwiftUI?

I am making a custom path in SwiftUI and fill it with red color, I want to give a border or stroke for my path. How we can do this?
struct ContentView: View
{
var body: some View
{
Path { path in
path.addArc(center: CGPoint(x: 100, y: 300), radius: 200, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
}
.fill(Color.red)
}
}
You'll need to stroke and fill the path separately. Here is one way to do it.
Assign your path to a variable, and then use that to fill it, and then overlay it with the same path stroked. Note: You need to use path.closeSubpath() to close your path, or only the arc will be stroked.
struct ContentView: View
{
var body: some View {
let path = Path { path in
path.addArc(center: CGPoint(x: 100, y: 300), radius: 200, startAngle: Angle(degrees: -90), endAngle: Angle(degrees: 0), clockwise: false)
path.closeSubpath()
}
path.fill(Color.red).overlay(path.stroke(Color.black, lineWidth: 2))
}
}
First start by declaring a custom Shape. You only have to implement func path(in rect: CGRect) -> Path :
struct Diamond: Shape {
func path(in rect: CGRect) -> Path {
let topMid = CGPoint(x: rect.midX, y: rect.minY)
let trailingMid = CGPoint(x: rect.maxX, y: rect.midY)
let bottomMid = CGPoint(x: rect.midX, y: rect.maxY)
let leadingMid = CGPoint(x: rect.minX, y: rect.midY)
var path = Path()
path.move(to: topMid)
path.addLine(to: trailingMid)
path.addLine(to: bottomMid)
path.addLine(to: leadingMid)
path.addLine(to: topMid)
return path
}
}
and then you can place in a ZStack: your background clipped to your custom shape and your custom shape with stroke applied:
struct ContentView: View {
var body: some View {
ZStack {
Color.blue
.clipShape(Diamond())
Diamond()
.stroke(Color.purple, lineWidth: 4)
} .padding()
}
}

SwiftUI, multiple shapes with unified shadow?

Is there a way in SwiftUI to union two shapes so that they cast a unified shadow. I have tried various combinations and modifiers but don't seem to be able to achieve the look I am after. Any insight would be much appreciated.
struct CardView: View {
var body: some View {
Group {
RoundedRectangle(cornerRadius: 20)
.fill(Color.orange)
.frame(width: 200, height: 250)
.zIndex(0)
Circle()
.trim(from: 0.5, to: 1)
.fill(Color.orange)
.frame(width: 100, height: 100)
.offset(y: -125)
.zIndex(1)
}.shadow(color: Color.black, radius: 10, x: 0, y: 0)
}
}
This is what I get, and what I am after ...
NOTE: zIndex was just something I tried, i.e. both shapes having the same zIndex etc. its also a quick way to reorder things without having to move the shapes within the container.
Here is possible solution. Tested with Xcode 11.4 / iOS 13.4
struct CardView: View {
var body: some View {
VStack(spacing: 0) {
Circle()
.trim(from: 0.5, to: 1)
.fill(Color.orange)
.frame(width: 100, height: 100)
.offset(x: 0, y: 50)
RoundedRectangle(cornerRadius: 20)
.fill(Color.orange)
.frame(width: 200, height: 250)
}
.compositingGroup()
.shadow(color: Color.primary, radius: 10, x: 0, y: 0)
}
}
I think the correct answer is #Asperi's .compositingGroup as documented here (https://developer.apple.com/documentation/swiftui/group/3284789-compositinggroup) but I'd like to leave a different working version because there are some use cases where you may not be able or want to use .compositingGroup.
So let's look at .background, you can copy and paste the code to see in the simulator:
import SwiftUI
struct AnyShapedView: View {
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 20)
.fill(Color.orange)
.frame(width: 200, height: 250)
.zIndex(0)
Circle()
.trim(from: 0.5, to: 1)
.fill(Color.orange)
.frame(width: 100, height: 100)
.offset(y: -125)
.zIndex(1)
}
}
}
struct ContentView: View {
var body: some View {
AnyShapedView()
.background(
AnyShapedView()
.shadow(color: Color.black, radius: 10, x: 0, y: 0)
)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The output:
The version above is not the best practice, but nevertheless, try to understand how shapes and cropping work, as in some use cases it might come useful.
Draw the shape:
struct CustomShape: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
path.move(to: CGPoint(x: 0.89995*width, y: 0.16667*height))
path.addLine(to: CGPoint(x: 0.75*width, y: 0.16667*height))
path.addCurve(to: CGPoint(x: 0.5*width, y: 0), control1: CGPoint(x: 0.75*width, y: 0.07463*height), control2: CGPoint(x: 0.63805*width, y: 0))
path.addCurve(to: CGPoint(x: 0.25*width, y: 0.16667*height), control1: CGPoint(x: 0.36195*width, y: 0), control2: CGPoint(x: 0.25*width, y: 0.07463*height))
path.addLine(to: CGPoint(x: 0.10005*width, y: 0.16667*height))
path.addCurve(to: CGPoint(x: 0, y: 0.23337*height), control1: CGPoint(x: 0.0448*width, y: 0.16667*height), control2: CGPoint(x: 0, y: 0.19653*height))
path.addLine(to: CGPoint(x: 0, y: 0.93333*height))
path.addCurve(to: CGPoint(x: 0.10005*width, y: 1.00003*height), control1: CGPoint(x: 0, y: 0.97017*height), control2: CGPoint(x: 0.0448*width, y: 1.00003*height))
path.addLine(to: CGPoint(x: 0.89995*width, y: 1.00003*height))
path.addCurve(to: CGPoint(x: width, y: 0.93333*height), control1: CGPoint(x: 0.9552*width, y: 1.00003*height), control2: CGPoint(x: width, y: 0.97017*height))
path.addLine(to: CGPoint(x: width, y: 0.23337*height))
path.addCurve(to: CGPoint(x: 0.89995*width, y: 0.16667*height), control1: CGPoint(x: width, y: 0.19653*height), control2: CGPoint(x: 0.9552*width, y: 0.16667*height))
path.closeSubpath()
return path
}
}
And custom color, shadow and size in your parent view:
CustomShape()
.fill(.orange)
.shadow(color: Color.primary, radius: 10, x: 0, y: 0)
.frame(width: 300, height: 400)

How do I color a SwiftUI Rectangle two different colors?

Supposing I have a simple SwiftUI Rectangle such as:
Rectangle()
.frame(width: 20, height: 20)
How can I color one half of it white at a 45 degree angle, and the other half black at a 45 degree angle?
My initial guess was to layer two Rectangles over each other with ZStack, but that way seems hacky to me.
Simple geometry can be achieved by transforming the shape:
Rectangle()
.rotation(.degrees(45), anchor: .bottomLeading)
.scale(sqrt(2), anchor: .bottomLeading)
.frame(width: 200, height: 200)
.background(Color.red)
.foregroundColor(Color.blue)
.clipped()
The least "hacky" way could be Gradients. With a code like this:
Rectangle()
.fill(
LinearGradient(
gradient: Gradient(stops: [
Gradient.Stop(color: .red, location: 0.5),
Gradient.Stop(color: .black, location: 0.5)
]),
startPoint: .topLeading,
endPoint: .bottomTrailing))
.frame(width: 200, height: 200)
You get a rectangle like this:
What actually happens is, that SwiftUI creates two color-gradients: One from 0.0 - 0.5, from red to red and a second gradient from 0.5 to 1.0 from black to black.
Also note, that the fill must immediately follow the path (here Rectangle) as it is the Shape variant of fill.
You should use path for drawing this. My idea is to put Rectangle and Triangle into ZStack:
struct GradientRectangle: View {
var body: some View {
ZStack {
Rectangle()
Triangle()
.foregroundColor(.red) // here should be .white in your case
}
.frame(width: 300, height: 300)
}
}
struct Triangle: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX, y: rect.maxY))
path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY))
return path
}
}
the result will be: