feat: 替换IP图标并对齐样式
This commit is contained in:
parent
135bebd0af
commit
1fa7d113fe
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.8 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 61 KiB |
@ -419,8 +419,8 @@ struct MainUploadArea: View {
|
||||
}
|
||||
}
|
||||
.background(Color.white)
|
||||
.cornerRadius(18)
|
||||
.animation(.default, value: selectedMedia?.id)
|
||||
.cornerRadius(16)
|
||||
.padding(Theme.Spacing.md)
|
||||
}
|
||||
|
||||
// MARK: - 子视图
|
||||
@ -599,6 +599,7 @@ struct MainUploadArea: View {
|
||||
struct UploadPromptView: View {
|
||||
/// 控制媒体选择器的显示/隐藏
|
||||
@Binding var showMediaPicker: Bool
|
||||
// 使用 TimelineView 基于时间驱动的相位,避免任何状态更新
|
||||
|
||||
var body: some View {
|
||||
Button(action: { showMediaPicker = true }) {
|
||||
@ -608,22 +609,44 @@ struct UploadPromptView: View {
|
||||
.frame(width: 225, height: 225)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.overlay(
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
.stroke(style: StrokeStyle(
|
||||
lineWidth: 5,
|
||||
lineCap: .round,
|
||||
dash: [12, 8]
|
||||
))
|
||||
.foregroundColor(Color.themePrimary)
|
||||
|
||||
// Add plus icon in the center
|
||||
.overlay(alignment: .center) {
|
||||
// Center plus icon
|
||||
Image(systemName: "plus")
|
||||
.font(.system(size: 32, weight: .bold))
|
||||
.foregroundColor(.black)
|
||||
}
|
||||
.overlay(alignment: .bottomTrailing) {
|
||||
// Bottom-right IP image
|
||||
Image("IP")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 80, height: 80)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.trailing, 18)
|
||||
}
|
||||
.overlay(
|
||||
TimelineView(.animation) { context in
|
||||
// 以 1.5s 为周期,0 -> 40 的相位
|
||||
let period: Double = 1.5
|
||||
let t = context.date.timeIntervalSinceReferenceDate
|
||||
let progress = (t.truncatingRemainder(dividingBy: period)) / period
|
||||
let phase = CGFloat(progress * 40.0)
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
.stroke(style: StrokeStyle(
|
||||
lineWidth: 4,
|
||||
lineCap: .round,
|
||||
dash: [12, 8],
|
||||
dashPhase: phase
|
||||
))
|
||||
.foregroundColor(Color.themePrimary)
|
||||
}
|
||||
)
|
||||
.padding(.bottom, Theme.Spacing.xl)
|
||||
}
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
// 完全禁用该视图树内的隐式动画,避免重绘对父级产生任何动画影响
|
||||
.transaction { tx in
|
||||
tx.disablesAnimations = true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -718,8 +741,6 @@ extension TimeInterval {
|
||||
|
||||
struct MediaUploadView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
MediaUploadView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,6 +72,14 @@ public struct AvatarPicker: View {
|
||||
.scaleEffect(scaleFactor)
|
||||
.contentShape(Rectangle())
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20 * scaleFactor))
|
||||
.overlay(alignment: .bottomTrailing) {
|
||||
Image("IP")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 80, height: 80)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.trailing, 18)
|
||||
}
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
.stroke(style: StrokeStyle(
|
||||
@ -129,6 +137,7 @@ public struct AvatarPicker: View {
|
||||
.frame(maxWidth: .infinity)
|
||||
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
||||
.animation(animation, value: isKeyboardVisible)
|
||||
.padding(.top, Theme.Spacing.md)
|
||||
}
|
||||
}
|
||||
.animation(animation, value: isKeyboardVisible)
|
||||
@ -247,6 +256,7 @@ public struct AvatarPicker: View {
|
||||
uploadManager.startUpload()
|
||||
}
|
||||
}
|
||||
.padding(.bottom, Theme.Spacing.md)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user