我正在尝试在 SwiftUI 中重新创建 Whatsapp 的消息回复功能。
基本上我有一个表示消息的视图,消息的最大宽度为 300。因此,当消息链接有较旧的消息(已回复的消息)时,它将被放置在消息的顶部就像whatsapp一样。
问题是,我希望旧消息扩展到与消息相同的大小。 (检查我附加的图片看看出了什么问题)
正如您在第二张图片中看到的,我需要深蓝色背景一直延伸。
但是,我不想让宽度无限大,因为我不希望它一直延伸,除非回复这样做。如果这是有道理的话。我只是想让旧的消息背景与回复相匹配,而不会让回复右侧有很多空白。
这是我的代码:
struct DMMessageBubbleReceiver: View{
let impactMed = UIImpactFeedbackGenerator(style: .medium)
@State var message: Message
@State private var showActionSheet = false
@State var userUID: String
@State var showEmojis = false
@State private var scale: CGFloat = 0.5
@State var emojis = ["😂", "❤️", "👍", "👎", "✈️", "☠️"]
@Binding var blurEverything: String
@ObservedObject var homeData = HomeViewModel.shared
@State private var offsetX: CGFloat = 0
@Binding var isReplying: Bool
@Binding var replyToMessage: MsgReply
var body: some View {
VStack(alignment: .leading, spacing: 0) {
if showEmojis {
HStack(spacing: 17) {
ForEach(emojis, id: \.self) { emoji in
Button(action: {
impactMed.impactOccurred()
withAnimation {
showEmojis.toggle()
blurEverything = ""
}
homeData.addRemoveEmoji(message: message, emoji: emoji, userUID: userUID)
}) {
Text(emoji)
.font(.custom("Poppins-Regular", fixedSize: 18))
}
}
}
.padding(.horizontal).padding(.vertical, 5)
.background(Color(UIColor.systemGray5).cornerRadius(50))
.padding(.bottom, 5)
.scaleEffect(scale)
.onAppear {
withAnimation(.easeInOut(duration: 0.3)) {
scale = 1.2
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
impactMed.impactOccurred()
withAnimation(.easeInOut(duration: 0.3)) {
scale = 1.0
}
}
}
}
}
HStack {
HStack {
if message.deleted != true {
ZStack(alignment: .bottomTrailing) {
VStack(alignment: .leading, spacing: 0){
if let reply = message.reply{
HStack{
VStack(alignment: .leading, spacing: 5){
Text("You")
.font(.custom("Gilroy-Medium", fixedSize: 12))
.foregroundColor(.blue)
.lineSpacing(5)
Text(reply.msg)
.font(.custom("Gilroy-Medium", fixedSize: 13))
.foregroundColor(.black)
.lineSpacing(5)
.lineLimit(3)
}
}.padding(10).background(Color.blue.opacity(0.07).cornerRadius(5)).padding(.horizontal, 5).padding(.top, 5)
}
Text(filterLinksInText(message.text))
.font(.custom("Gilroy-Medium", fixedSize: 15))
.foregroundColor(.black)
.lineSpacing(5)
.padding(.vertical, 14).padding(.leading, 10).padding(.trailing, 15)
}
.background(Color(UIColor.systemGray5).opacity(0.6))
.cornerRadius(12, corners: [.topLeft, .topRight, .bottomRight])
.offset(x: offsetX)
.gesture(
DragGesture()
.onChanged { value in
if message.deleted == false {
if value.translation.width > 0 {
offsetX = value.translation.width
}
}
}
.onEnded { value in
if offsetX > 100 {
impactMed.impactOccurred()
withAnimation {
isReplying = true
replyToMessage = MsgReply(id: message.id, msg: message.text, name: "name")
offsetX = 0
}
} else {
withAnimation {
offsetX = 0
}
}
}
)
if message.emoji != "" {
Text(message.emoji)
.font(.system(size: 12))
.foregroundColor(.red)
.padding(3)
.background(Color("messagebackground"))
.cornerRadius(50)
.offset(y: 8)
.offset(x: 8)
}
}
} else {
Text("This message was deleted")
.font(Font.system(size: 13))
.italic()
.fontWeight(.medium)
.foregroundColor(.black.opacity(0.6))
.padding(.horizontal)
.padding(.vertical, 10)
.background(Color(UIColor.systemGray5))
.cornerRadius(12, corners: [.topLeft, .topRight, .bottomRight])
}
}
.frame(maxWidth: 300, alignment: .leading)
Spacer()
ZStack(alignment: .bottomTrailing) {
Text(" ")
}.padding(.trailing)
}
Text("\(message.timestamp.formatted(.dateTime.hour().minute()))")
.font(.custom("Gilroy-Medium", fixedSize: 11))
.foregroundColor(.black.opacity(0.3))
.padding(.leading, 5).padding(.top, 8).padding(.bottom, 10)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.leading)
.padding(.horizontal, 10)
.blur(radius: (blurEverything != "" && blurEverything != message.id) ? 2 : 0)
.onTapGesture(count: 2) {
if message.deleted != true{
self.likeMessage(message: message)
}
}
.onTapGesture(count: 1) {
if message.deleted == false {
withAnimation {
showEmojis.toggle()
if blurEverything != "" {
blurEverything = ""
} else {
blurEverything = message.id
}
}
}
}
.onLongPressGesture {
showActionSheet = true
}
.actionSheet(isPresented: $showActionSheet) {
ActionSheet(title: Text("Message Options"), buttons: getButtons(message: message))
}
}
func getButtons(message: Message) -> [ActionSheet.Button] {
var buttons: [ActionSheet.Button] = []
if message.deleted != true {
buttons.append(.default(Text("Copy"), action: {
self.copyText(message: message.text)
}))
}
if message.deleted != true {
if message.numLikes > 0 {
buttons.append(.default(Text("Unlike"), action: { self.likeMessage(message: message) }))
} else {
buttons.append(.default(Text("Like"), action: { self.likeMessage(message: message) }))
}
}
if message.deleted == false {
buttons.append(.destructive(Text("Delete"), action: {
self.deleteMessage()
}))
}
buttons.append(.cancel(Text("Cancel")))
return buttons
}
func copyText(message: String) {
UIPasteboard.general.string = message
}
func likeMessage(message: Message) {
impactMed.impactOccurred()
homeData.likeDMMessage(message: message, userUID: userUID)
}
func deleteMessage() {
impactMed.impactOccurred()
homeData.deleteDMMessage(userUID: userUID, message: message)
}
func filterLinksInText(_ text: String) -> String {
do {
let regexPattern = try NSRegularExpression(pattern: "https?://([-\\w\\.]+)+(:\\d+)?(/([\\w/_\\.]*(\\?\\S+)?)?)?", options: .caseInsensitive)
let modifiedText = regexPattern.stringByReplacingMatches(
in: text,
options: [],
range: NSRange(location: 0, length: text.utf16.count),
withTemplate: "****"
)
return modifiedText
} catch {
return text
}
}
}