Created
July 22, 2020 12:26
-
-
Save prafullakumar/aa7af213d9e7530ee82aa6e8c92505b4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// ChatBubble.swift | |
// ios14-demo | |
// | |
// Created by Prafulla Singh on 25/7/20. | |
// | |
import SwiftUI | |
struct ChatBubble<Content>: View where Content: View { | |
let direction: ChatBubbleShape.Direction | |
let content: () -> Content | |
init(direction: ChatBubbleShape.Direction, @ViewBuilder content: @escaping () -> Content) { | |
self.content = content | |
self.direction = direction | |
} | |
var body: some View { | |
HStack { | |
if direction == .right { | |
Spacer() | |
} | |
content().clipShape(ChatBubbleShape(direction: direction)) | |
if direction == .left { | |
Spacer() | |
} | |
}.padding([(direction == .left) ? .leading : .trailing, .top, .bottom], 20) | |
.padding((direction == .right) ? .leading : .trailing, 50) | |
} | |
} | |
struct ChatBubbleShape: Shape { | |
enum Direction { | |
case left | |
case right | |
} | |
let direction: Direction | |
func path(in rect: CGRect) -> Path { | |
return (direction == .left) ? getLeftBubblePath(in: rect) : getRightBubblePath(in: rect) | |
} | |
private func getLeftBubblePath(in rect: CGRect) -> Path { | |
let width = rect.width | |
let height = rect.height | |
let path = Path { p in | |
p.move(to: CGPoint(x: 25, y: height)) | |
p.addLine(to: CGPoint(x: width - 20, y: height)) | |
p.addCurve(to: CGPoint(x: width, y: height - 20), | |
control1: CGPoint(x: width - 8, y: height), | |
control2: CGPoint(x: width, y: height - 8)) | |
p.addLine(to: CGPoint(x: width, y: 20)) | |
p.addCurve(to: CGPoint(x: width - 20, y: 0), | |
control1: CGPoint(x: width, y: 8), | |
control2: CGPoint(x: width - 8, y: 0)) | |
p.addLine(to: CGPoint(x: 21, y: 0)) | |
p.addCurve(to: CGPoint(x: 4, y: 20), | |
control1: CGPoint(x: 12, y: 0), | |
control2: CGPoint(x: 4, y: 8)) | |
p.addLine(to: CGPoint(x: 4, y: height - 11)) | |
p.addCurve(to: CGPoint(x: 0, y: height), | |
control1: CGPoint(x: 4, y: height - 1), | |
control2: CGPoint(x: 0, y: height)) | |
p.addLine(to: CGPoint(x: -0.05, y: height - 0.01)) | |
p.addCurve(to: CGPoint(x: 11.0, y: height - 4.0), | |
control1: CGPoint(x: 4.0, y: height + 0.5), | |
control2: CGPoint(x: 8, y: height - 1)) | |
p.addCurve(to: CGPoint(x: 25, y: height), | |
control1: CGPoint(x: 16, y: height), | |
control2: CGPoint(x: 20, y: height)) | |
} | |
return path | |
} | |
private func getRightBubblePath(in rect: CGRect) -> Path { | |
let width = rect.width | |
let height = rect.height | |
let path = Path { p in | |
p.move(to: CGPoint(x: 25, y: height)) | |
p.addLine(to: CGPoint(x: 20, y: height)) | |
p.addCurve(to: CGPoint(x: 0, y: height - 20), | |
control1: CGPoint(x: 8, y: height), | |
control2: CGPoint(x: 0, y: height - 8)) | |
p.addLine(to: CGPoint(x: 0, y: 20)) | |
p.addCurve(to: CGPoint(x: 20, y: 0), | |
control1: CGPoint(x: 0, y: 8), | |
control2: CGPoint(x: 8, y: 0)) | |
p.addLine(to: CGPoint(x: width - 21, y: 0)) | |
p.addCurve(to: CGPoint(x: width - 4, y: 20), | |
control1: CGPoint(x: width - 12, y: 0), | |
control2: CGPoint(x: width - 4, y: 8)) | |
p.addLine(to: CGPoint(x: width - 4, y: height - 11)) | |
p.addCurve(to: CGPoint(x: width, y: height), | |
control1: CGPoint(x: width - 4, y: height - 1), | |
control2: CGPoint(x: width, y: height)) | |
p.addLine(to: CGPoint(x: width + 0.05, y: height - 0.01)) | |
p.addCurve(to: CGPoint(x: width - 11, y: height - 4), | |
control1: CGPoint(x: width - 4, y: height + 0.5), | |
control2: CGPoint(x: width - 8, y: height - 1)) | |
p.addCurve(to: CGPoint(x: width - 25, y: height), | |
control1: CGPoint(x: width - 16, y: height), | |
control2: CGPoint(x: width - 20, y: height)) | |
} | |
return path | |
} | |
} | |
struct Demo: View { | |
var body: some View { | |
ScrollView { | |
VStack { | |
ChatBubble(direction: .left) { | |
Text("Hello!") | |
.padding(.all, 20) | |
.foregroundColor(Color.white) | |
.background(Color.blue) | |
} | |
ChatBubble(direction: .right) { | |
Text("Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ut semper quam. Phasellus non mauris sem. Donec sed fermentum eros. Donec pretium nec turpis a semper. ") | |
.padding(.all, 20) | |
.foregroundColor(Color.white) | |
.background(Color.blue) | |
} | |
ChatBubble(direction: .right) { | |
Image.init("dummyImage") | |
.resizable() | |
.frame(width: UIScreen.main.bounds.width - 70, | |
height: 200).aspectRatio(contentMode: .fill) | |
} | |
} | |
} | |
} | |
} | |
struct ChatBubble_Previews: PreviewProvider { | |
static var previews: some View { | |
Demo() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment