룰렛 설정 입력 가시성과 프로필 메뉴 레이아웃 개선
룰렛 설정에서 입력 필드 포커스 시 항목을 중앙으로 이동한다. 키보드에 가려지지 않도록 입력 가시성을 높인다. 프로필 메뉴 오버레이의 하단 안전영역 패딩을 제거한다.
This commit is contained in:
@@ -541,7 +541,6 @@ struct UserProfileView: View {
|
|||||||
viewModel.isShowPopup = true
|
viewModel.isShowPopup = true
|
||||||
}
|
}
|
||||||
.padding(.top, proxy.safeAreaInsets.top)
|
.padding(.top, proxy.safeAreaInsets.top)
|
||||||
.padding(.bottom, proxy.safeAreaInsets.bottom)
|
|
||||||
.padding(.trailing, proxy.safeAreaInsets.trailing)
|
.padding(.trailing, proxy.safeAreaInsets.trailing)
|
||||||
.padding(.leading, proxy.safeAreaInsets.leading)
|
.padding(.leading, proxy.safeAreaInsets.leading)
|
||||||
}
|
}
|
||||||
@@ -549,7 +548,6 @@ struct UserProfileView: View {
|
|||||||
if isShowMenuSettings {
|
if isShowMenuSettings {
|
||||||
MenuSettingsView(isShowing: $isShowMenuSettings)
|
MenuSettingsView(isShowing: $isShowMenuSettings)
|
||||||
.padding(.top, proxy.safeAreaInsets.top)
|
.padding(.top, proxy.safeAreaInsets.top)
|
||||||
.padding(.bottom, proxy.safeAreaInsets.bottom)
|
|
||||||
.padding(.trailing, proxy.safeAreaInsets.trailing)
|
.padding(.trailing, proxy.safeAreaInsets.trailing)
|
||||||
.padding(.leading, proxy.safeAreaInsets.leading)
|
.padding(.leading, proxy.safeAreaInsets.leading)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
class RouletteOption: ObservableObject {
|
class RouletteOption: ObservableObject, Identifiable {
|
||||||
var title: String
|
let id = UUID()
|
||||||
var percentage: String = ""
|
|
||||||
|
@Published var title: String
|
||||||
|
@Published var percentage: String = ""
|
||||||
|
|
||||||
init(title: String, percentage: String) {
|
init(title: String, percentage: String) {
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ struct RouletteSettingsOptionView: View {
|
|||||||
@ObservedObject var option: RouletteOption
|
@ObservedObject var option: RouletteOption
|
||||||
|
|
||||||
let index: Int
|
let index: Int
|
||||||
|
var focusedField: FocusState<RouletteSettingsFocusField?>.Binding
|
||||||
let onClickDelete: () -> Void
|
let onClickDelete: () -> Void
|
||||||
let calculateTotalPercentage: () -> Void
|
let calculateTotalPercentage: () -> Void
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@ struct RouletteSettingsOptionView: View {
|
|||||||
.appFont(size: 13.3, weight: .medium)
|
.appFont(size: 13.3, weight: .medium)
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.keyboardType(.default)
|
.keyboardType(.default)
|
||||||
|
.focused(focusedField, equals: .optionTitle(option.id))
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.padding(.vertical, 16.7)
|
.padding(.vertical, 16.7)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
@@ -52,6 +54,7 @@ struct RouletteSettingsOptionView: View {
|
|||||||
.appFont(size: 13.3, weight: .medium)
|
.appFont(size: 13.3, weight: .medium)
|
||||||
.foregroundColor(Color(hex: "eeeeee"))
|
.foregroundColor(Color(hex: "eeeeee"))
|
||||||
.keyboardType(.decimalPad)
|
.keyboardType(.decimalPad)
|
||||||
|
.focused(focusedField, equals: .optionPercentage(option.id))
|
||||||
.onChange(of: option.percentage) { newValue in
|
.onChange(of: option.percentage) { newValue in
|
||||||
if newValue.count > 5 {
|
if newValue.count > 5 {
|
||||||
option.percentage = String(newValue.prefix(5))
|
option.percentage = String(newValue.prefix(5))
|
||||||
@@ -76,9 +79,18 @@ struct RouletteSettingsOptionView: View {
|
|||||||
|
|
||||||
struct RouletteSettingsOptionView_Previews: PreviewProvider {
|
struct RouletteSettingsOptionView_Previews: PreviewProvider {
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
|
PreviewContainer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct PreviewContainer: View {
|
||||||
|
@FocusState private var focusedField: RouletteSettingsFocusField?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
RouletteSettingsOptionView(
|
RouletteSettingsOptionView(
|
||||||
option: RouletteOption(title: "옵션1", percentage: ""),
|
option: RouletteOption(title: "옵션1", percentage: ""),
|
||||||
index: 2,
|
index: 2,
|
||||||
|
focusedField: $focusedField,
|
||||||
onClickDelete: {},
|
onClickDelete: {},
|
||||||
calculateTotalPercentage: {}
|
calculateTotalPercentage: {}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,10 +7,17 @@
|
|||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
|
enum RouletteSettingsFocusField: Hashable {
|
||||||
|
case canAmount
|
||||||
|
case optionTitle(UUID)
|
||||||
|
case optionPercentage(UUID)
|
||||||
|
}
|
||||||
|
|
||||||
struct RouletteSettingsView: View {
|
struct RouletteSettingsView: View {
|
||||||
|
|
||||||
@StateObject var keyboardHandler = KeyboardHandler()
|
@StateObject var keyboardHandler = KeyboardHandler()
|
||||||
@StateObject var viewModel = RouletteSettingsViewModel()
|
@StateObject var viewModel = RouletteSettingsViewModel()
|
||||||
|
@FocusState private var focusedField: RouletteSettingsFocusField?
|
||||||
|
|
||||||
@Binding var isShowing: Bool
|
@Binding var isShowing: Bool
|
||||||
|
|
||||||
@@ -25,8 +32,9 @@ struct RouletteSettingsView: View {
|
|||||||
isShowing = false
|
isShowing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollView(.vertical, showsIndicators: false) {
|
ScrollViewReader { scrollProxy in
|
||||||
VStack(spacing: 0) {
|
ScrollView(.vertical, showsIndicators: false) {
|
||||||
|
VStack(spacing: 0) {
|
||||||
HStack(spacing: 13.3) {
|
HStack(spacing: 13.3) {
|
||||||
SelectedButtonView(
|
SelectedButtonView(
|
||||||
title: I18n.Common.roulette1,
|
title: I18n.Common.roulette1,
|
||||||
@@ -100,6 +108,7 @@ struct RouletteSettingsView: View {
|
|||||||
.appFont(size: 13.3, weight: .medium)
|
.appFont(size: 13.3, weight: .medium)
|
||||||
.foregroundColor(Color.grayee)
|
.foregroundColor(Color.grayee)
|
||||||
.keyboardType(.numberPad)
|
.keyboardType(.numberPad)
|
||||||
|
.focused($focusedField, equals: .canAmount)
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.padding(.vertical, 16.7)
|
.padding(.vertical, 16.7)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity)
|
||||||
@@ -114,6 +123,7 @@ struct RouletteSettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 26.7)
|
.padding(.top, 26.7)
|
||||||
|
.id("roulette_can_input")
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: 21.3) {
|
VStack(alignment: .leading, spacing: 21.3) {
|
||||||
Text("룰렛 옵션 설정")
|
Text("룰렛 옵션 설정")
|
||||||
@@ -146,20 +156,31 @@ struct RouletteSettingsView: View {
|
|||||||
}
|
}
|
||||||
.padding(.top, 21.3)
|
.padding(.top, 21.3)
|
||||||
|
|
||||||
LazyVStack(spacing: 21.3) {
|
VStack(spacing: 21.3) {
|
||||||
ForEach(viewModel.options.indices, id: \.self) { index in
|
ForEach(Array(viewModel.options.enumerated()), id: \.element.id) { index, option in
|
||||||
RouletteSettingsOptionView(
|
RouletteSettingsOptionView(
|
||||||
option: viewModel.options[index],
|
option: option,
|
||||||
index: index,
|
index: index,
|
||||||
|
focusedField: $focusedField,
|
||||||
onClickDelete: { viewModel.deleteOption(index: index) },
|
onClickDelete: { viewModel.deleteOption(index: index) },
|
||||||
calculateTotalPercentage: { viewModel.calculateTotalPercentage() }
|
calculateTotalPercentage: { viewModel.calculateTotalPercentage() }
|
||||||
)
|
)
|
||||||
|
.id(option.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.top, 21.3)
|
.padding(.top, 21.3)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 13.3)
|
.padding(.horizontal, 13.3)
|
||||||
.padding(.bottom, keyboardHandler.keyboardHeight)
|
.padding(.bottom, keyboardHandler.keyboardHeight)
|
||||||
|
.onChange(of: focusedField) { _ in
|
||||||
|
scrollToFocusedField(scrollProxy: scrollProxy)
|
||||||
|
}
|
||||||
|
.onChange(of: keyboardHandler.keyboardHeight) { height in
|
||||||
|
if height > 0, focusedField != nil {
|
||||||
|
scrollToFocusedField(scrollProxy: scrollProxy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
@@ -204,6 +225,7 @@ struct RouletteSettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
|
focusedField = nil
|
||||||
hideKeyboard()
|
hideKeyboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +262,19 @@ struct RouletteSettingsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func scrollToFocusedField(scrollProxy: ScrollViewProxy) {
|
||||||
|
guard let focusedField else { return }
|
||||||
|
|
||||||
|
withAnimation(.easeOut(duration: 0.2)) {
|
||||||
|
switch focusedField {
|
||||||
|
case .canAmount:
|
||||||
|
scrollProxy.scrollTo("roulette_can_input", anchor: .center)
|
||||||
|
case .optionTitle(let id), .optionPercentage(let id):
|
||||||
|
scrollProxy.scrollTo(id, anchor: .center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RouletteSettingsView_Previews: PreviewProvider {
|
struct RouletteSettingsView_Previews: PreviewProvider {
|
||||||
|
|||||||
Reference in New Issue
Block a user