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)
|
.background(Color.white)
|
||||||
.cornerRadius(18)
|
.cornerRadius(16)
|
||||||
.animation(.default, value: selectedMedia?.id)
|
.padding(Theme.Spacing.md)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - 子视图
|
// MARK: - 子视图
|
||||||
@ -574,11 +574,11 @@ struct MainUploadArea: View {
|
|||||||
/// 添加更多按钮
|
/// 添加更多按钮
|
||||||
private var addMoreButton: some View {
|
private var addMoreButton: some View {
|
||||||
Button(action: { showMediaPicker = true }) {
|
Button(action: { showMediaPicker = true }) {
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
.font(.system(size: 8, weight: .bold))
|
.font(.system(size: 8, weight: .bold))
|
||||||
.foregroundColor(.black)
|
.foregroundColor(.black)
|
||||||
.frame(width: 58, height: 58)
|
.frame(width: 58, height: 58)
|
||||||
.background(Color.white)
|
.background(Color.white)
|
||||||
.cornerRadius(8)
|
.cornerRadius(8)
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 8)
|
RoundedRectangle(cornerRadius: 8)
|
||||||
@ -599,6 +599,7 @@ struct MainUploadArea: View {
|
|||||||
struct UploadPromptView: View {
|
struct UploadPromptView: View {
|
||||||
/// 控制媒体选择器的显示/隐藏
|
/// 控制媒体选择器的显示/隐藏
|
||||||
@Binding var showMediaPicker: Bool
|
@Binding var showMediaPicker: Bool
|
||||||
|
// 使用 TimelineView 基于时间驱动的相位,避免任何状态更新
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Button(action: { showMediaPicker = true }) {
|
Button(action: { showMediaPicker = true }) {
|
||||||
@ -608,22 +609,44 @@ struct UploadPromptView: View {
|
|||||||
.frame(width: 225, height: 225)
|
.frame(width: 225, height: 225)
|
||||||
}
|
}
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
|
.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(
|
.overlay(
|
||||||
ZStack {
|
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)
|
RoundedRectangle(cornerRadius: 20)
|
||||||
.stroke(style: StrokeStyle(
|
.stroke(style: StrokeStyle(
|
||||||
lineWidth: 5,
|
lineWidth: 4,
|
||||||
lineCap: .round,
|
lineCap: .round,
|
||||||
dash: [12, 8]
|
dash: [12, 8],
|
||||||
|
dashPhase: phase
|
||||||
))
|
))
|
||||||
.foregroundColor(Color.themePrimary)
|
.foregroundColor(Color.themePrimary)
|
||||||
|
|
||||||
// Add plus icon in the center
|
|
||||||
Image(systemName: "plus")
|
|
||||||
.font(.system(size: 32, weight: .bold))
|
|
||||||
.foregroundColor(.black)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
.padding(.bottom, Theme.Spacing.xl)
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
// 完全禁用该视图树内的隐式动画,避免重绘对父级产生任何动画影响
|
||||||
|
.transaction { tx in
|
||||||
|
tx.disablesAnimations = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -718,8 +741,6 @@ extension TimeInterval {
|
|||||||
|
|
||||||
struct MediaUploadView_Previews: PreviewProvider {
|
struct MediaUploadView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
NavigationView {
|
MediaUploadView()
|
||||||
MediaUploadView()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,6 +72,14 @@ public struct AvatarPicker: View {
|
|||||||
.scaleEffect(scaleFactor)
|
.scaleEffect(scaleFactor)
|
||||||
.contentShape(Rectangle())
|
.contentShape(Rectangle())
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 20 * scaleFactor))
|
.clipShape(RoundedRectangle(cornerRadius: 20 * scaleFactor))
|
||||||
|
.overlay(alignment: .bottomTrailing) {
|
||||||
|
Image("IP")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 80, height: 80)
|
||||||
|
.padding(.bottom, 10)
|
||||||
|
.padding(.trailing, 18)
|
||||||
|
}
|
||||||
.overlay(
|
.overlay(
|
||||||
RoundedRectangle(cornerRadius: 20)
|
RoundedRectangle(cornerRadius: 20)
|
||||||
.stroke(style: StrokeStyle(
|
.stroke(style: StrokeStyle(
|
||||||
@ -129,6 +137,7 @@ public struct AvatarPicker: View {
|
|||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
.transition(.opacity.combined(with: .move(edge: .bottom)))
|
||||||
.animation(animation, value: isKeyboardVisible)
|
.animation(animation, value: isKeyboardVisible)
|
||||||
|
.padding(.top, Theme.Spacing.md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(animation, value: isKeyboardVisible)
|
.animation(animation, value: isKeyboardVisible)
|
||||||
@ -247,6 +256,7 @@ public struct AvatarPicker: View {
|
|||||||
uploadManager.startUpload()
|
uploadManager.startUpload()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.padding(.bottom, Theme.Spacing.md)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user