Skip to content

Instantly share code, notes, and snippets.

@prafullakumar
Created July 22, 2020 12:26
Show Gist options
  • Save prafullakumar/aa7af213d9e7530ee82aa6e8c92505b4 to your computer and use it in GitHub Desktop.
Save prafullakumar/aa7af213d9e7530ee82aa6e8c92505b4 to your computer and use it in GitHub Desktop.
//
// 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