Open3
SwiftUI
TextField のプレイスホルダーテキストのカラー
TextField(
"",
text: $topping,
prompt:
Text("Phone, email or username")
.foregroundColor(.accentColor)
)
Grid のUIのコード
import SwiftUI
struct PremiumPlanView: View {
@Binding var plans: [Plan]
private let columns: [GridItem] = Array(repeating: .init(spacing: 16), count: 2)
@State var selectedPlan: Plan.ProductId?
var body: some View {
Grid(horizontalSpacing: 16, verticalSpacing: 16) {
if plans.count > 3 {
GridRow {
ForEach(0..<2) { index in
RoundedRectangle(cornerRadius: 16)
.stroke(lineWidth: 2)
.foregroundColor(
Color.accentColor
)
.frame(height: 180)
.overlay {
VStack(alignment: .leading) {
HStack(alignment: .top) {
Text(plans[index].displayName)
.font(.title3)
.fontWeight(.black)
Spacer()
Image(
systemName: isSelected(plan: plans[index]) ? "checkmark.circle.fill" : "circle"
)
.resizable()
.scaledToFit()
.frame(height: 17)
}
.frame(alignment: .top)
.padding(.bottom, 8)
ForEach(plans[index].displayDescriptions, id: \.self) { description in
Text(description)
.font(
.system(
size: 14,
weight: .regular,
design: .default
)
)
}
Spacer()
HStack {
Spacer()
Text(plans[index].displayPeriod)
.font(
.system(
size: 14,
weight: .medium,
design: .default
)
)
Text(plans[index].displayPrice)
.font(.title3)
.fontWeight(.black)
}
}
.foregroundColor(
isSelected(plan: plans[index]) ? Color(.systemBackground) : Color.accentColor
)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
}
.background(
isSelected(plan: plans[index]) ? Color.accentColor : Color(.systemBackground)
)
.mask {
RoundedRectangle(cornerRadius: 16)
}
.onTapGesture {
selectedPlan = plans[index].productId
}
}
}
GridRow {
ForEach(2..<4) { index in
RoundedRectangle(cornerRadius: 16)
.stroke(lineWidth: 2)
.foregroundColor(
Color.accentColor
)
.frame(height: 180)
.overlay {
VStack(alignment: .leading) {
HStack(alignment: .top) {
Text(plans[index].displayName)
.font(.title3)
.fontWeight(.black)
Spacer()
Image(
systemName: isSelected(plan: plans[index]) ? "checkmark.circle.fill" : "circle"
)
.resizable()
.scaledToFit()
.frame(height: 17)
}
.frame(alignment: .top)
.padding(.bottom, 8)
ForEach(plans[index].displayDescriptions, id: \.self) { description in
Text(description)
.font(
.system(
size: 14,
weight: .regular,
design: .default
)
)
}
Spacer()
HStack {
Spacer()
Text(plans[index].displayPeriod)
.font(
.system(
size: 14,
weight: .medium,
design: .default
)
)
Text(plans[index].displayPrice)
.font(.title3)
.fontWeight(.black)
}
}
.foregroundColor(
isSelected(plan: plans[index]) ? Color(.systemBackground) : Color.accentColor
)
.frame(maxWidth: .infinity, alignment: .leading)
.padding(16)
}
.background(
isSelected(plan: plans[index]) ? Color.accentColor : Color(.systemBackground)
)
.mask {
RoundedRectangle(cornerRadius: 16)
}
.onTapGesture {
selectedPlan = plans[index].productId
}
}
}
}
}
.padding(.horizontal, 16)
}
func isSelected(plan: Plan) -> Bool {
return selectedPlan == plan.productId
}
}
#Preview {
PremiumPlanView(plans:
.constant(
[
// Plan(
// id: Plan.ProductId.monthlyFreeAdPlan.rawValue,
// displayName: "広告ゼロ\nプラン",
// displayPrice: "¥300",
// displayIntroductoryOfferPeriod: 1,
// displayIntroductoryOfferUnit: ""
// ),
// Plan(
// id: Plan.ProductId.monthlyReadaloudPlan.rawValue,
// displayName: "読み上げ\n強化プラン",
// displayPrice: "¥500", displayIntroductoryOfferPeriod: 1,
// displayIntroductoryOfferUnit: ""
// ),
// Plan(
// id: Plan.ProductId.monthlyRevisePlan.rawValue,
// displayName: "添削\n強化プラン",
// displayPrice: "¥500", displayIntroductoryOfferPeriod: 1,
// displayIntroductoryOfferUnit: ""
// ),
Plan(
id: Plan.ProductId.monthlyPremiumPlan.rawValue,
displayName: "よくばり\nプラン",
displayPrice: "¥800", displayIntroductoryOfferPeriod: 1,
displayIntroductoryOfferUnit: ""
)
]
)
)
}
ボタンタップして翻訳
@State private var isTranslationPresenting = false
Button {
isTranslationPresenting.toggle()
} label: {
Text("日記を翻訳する")
Spacer()
}
.translationPresentation(
isPresented: $isTranslationPresenting,
text: entry.displayContent
)