Swift UI - 하프 모달?
저는 스위프트의 iOS13에 있는 사파리처럼 모달을 재현하려고 합니다.UI:
다음은 다음과 같습니다.
스위프트에서 이게 가능한지 아는 사람?UI? 공유 시트처럼 전체 화면으로 끌 수 있는 옵션이 있는 작은 하프 모달을 보여주고 싶습니다.
어떤 조언이든 감사합니다!
Swift 5.5 iOS 15+ 및 Mac Catalyst 15+에는 다음이 있습니다.
다음과 같은 새로운 솔루션이 있습니다.adaptiveSheetPresentationController
@available(iOS 15.0, *)
struct CustomSheetParentView: View {
@State private var isPresented = false
var body: some View {
VStack{
Button("present sheet", action: {
isPresented.toggle()
}).adaptiveSheet(isPresented: $isPresented, detents: [.medium()], smallestUndimmedDetentIdentifier: .large){
Rectangle()
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.foregroundColor(.clear)
.border(Color.blue, width: 3)
.overlay(Text("Hello, World!").frame(maxWidth: .infinity, maxHeight: .infinity)
.onTapGesture {
isPresented.toggle()
}
)
}
}
}
}
@available(iOS 15.0, *)
struct AdaptiveSheet<T: View>: ViewModifier {
let sheetContent: T
@Binding var isPresented: Bool
let detents : [UISheetPresentationController.Detent]
let smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier?
let prefersScrollingExpandsWhenScrolledToEdge: Bool
let prefersEdgeAttachedInCompactHeight: Bool
init(isPresented: Binding<Bool>, detents : [UISheetPresentationController.Detent] = [.medium(), .large()], smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> T) {
self.sheetContent = content()
self.detents = detents
self.smallestUndimmedDetentIdentifier = smallestUndimmedDetentIdentifier
self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight
self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge
self._isPresented = isPresented
}
func body(content: Content) -> some View {
ZStack{
content
CustomSheet_UI(isPresented: $isPresented, detents: detents, smallestUndimmedDetentIdentifier: smallestUndimmedDetentIdentifier, prefersScrollingExpandsWhenScrolledToEdge: prefersScrollingExpandsWhenScrolledToEdge, prefersEdgeAttachedInCompactHeight: prefersEdgeAttachedInCompactHeight, content: {sheetContent}).frame(width: 0, height: 0)
}
}
}
@available(iOS 15.0, *)
extension View {
func adaptiveSheet<T: View>(isPresented: Binding<Bool>, detents : [UISheetPresentationController.Detent] = [.medium(), .large()], smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> T)-> some View {
modifier(AdaptiveSheet(isPresented: isPresented, detents : detents, smallestUndimmedDetentIdentifier: smallestUndimmedDetentIdentifier, prefersScrollingExpandsWhenScrolledToEdge: prefersScrollingExpandsWhenScrolledToEdge, prefersEdgeAttachedInCompactHeight: prefersEdgeAttachedInCompactHeight, content: content))
}
}
@available(iOS 15.0, *)
struct CustomSheet_UI<Content: View>: UIViewControllerRepresentable {
let content: Content
@Binding var isPresented: Bool
let detents : [UISheetPresentationController.Detent]
let smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier?
let prefersScrollingExpandsWhenScrolledToEdge: Bool
let prefersEdgeAttachedInCompactHeight: Bool
init(isPresented: Binding<Bool>, detents : [UISheetPresentationController.Detent] = [.medium(), .large()], smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> Content) {
self.content = content()
self.detents = detents
self.smallestUndimmedDetentIdentifier = smallestUndimmedDetentIdentifier
self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight
self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge
self._isPresented = isPresented
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> CustomSheetViewController<Content> {
let vc = CustomSheetViewController(coordinator: context.coordinator, detents : detents, smallestUndimmedDetentIdentifier: smallestUndimmedDetentIdentifier, prefersScrollingExpandsWhenScrolledToEdge: prefersScrollingExpandsWhenScrolledToEdge, prefersEdgeAttachedInCompactHeight: prefersEdgeAttachedInCompactHeight, content: {content})
return vc
}
func updateUIViewController(_ uiViewController: CustomSheetViewController<Content>, context: Context) {
if isPresented{
uiViewController.presentModalView()
}else{
uiViewController.dismissModalView()
}
}
class Coordinator: NSObject, UIAdaptivePresentationControllerDelegate {
var parent: CustomSheet_UI
init(_ parent: CustomSheet_UI) {
self.parent = parent
}
//Adjust the variable when the user dismisses with a swipe
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
if parent.isPresented{
parent.isPresented = false
}
}
}
}
@available(iOS 15.0, *)
class CustomSheetViewController<Content: View>: UIViewController {
let content: Content
let coordinator: CustomSheet_UI<Content>.Coordinator
let detents : [UISheetPresentationController.Detent]
let smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier?
let prefersScrollingExpandsWhenScrolledToEdge: Bool
let prefersEdgeAttachedInCompactHeight: Bool
private var isLandscape: Bool = UIDevice.current.orientation.isLandscape
init(coordinator: CustomSheet_UI<Content>.Coordinator, detents : [UISheetPresentationController.Detent] = [.medium(), .large()], smallestUndimmedDetentIdentifier: UISheetPresentationController.Detent.Identifier? = .medium, prefersScrollingExpandsWhenScrolledToEdge: Bool = false, prefersEdgeAttachedInCompactHeight: Bool = true, @ViewBuilder content: @escaping () -> Content) {
self.content = content()
self.coordinator = coordinator
self.detents = detents
self.smallestUndimmedDetentIdentifier = smallestUndimmedDetentIdentifier
self.prefersEdgeAttachedInCompactHeight = prefersEdgeAttachedInCompactHeight
self.prefersScrollingExpandsWhenScrolledToEdge = prefersScrollingExpandsWhenScrolledToEdge
super.init(nibName: nil, bundle: .main)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func dismissModalView(){
dismiss(animated: true, completion: nil)
}
func presentModalView(){
let hostingController = UIHostingController(rootView: content)
hostingController.modalPresentationStyle = .popover
hostingController.presentationController?.delegate = coordinator as UIAdaptivePresentationControllerDelegate
hostingController.modalTransitionStyle = .coverVertical
if let hostPopover = hostingController.popoverPresentationController {
hostPopover.sourceView = super.view
let sheet = hostPopover.adaptiveSheetPresentationController
//As of 13 Beta 4 if .medium() is the only detent in landscape error occurs
sheet.detents = (isLandscape ? [.large()] : detents)
sheet.largestUndimmedDetentIdentifier =
smallestUndimmedDetentIdentifier
sheet.prefersScrollingExpandsWhenScrolledToEdge =
prefersScrollingExpandsWhenScrolledToEdge
sheet.prefersEdgeAttachedInCompactHeight =
prefersEdgeAttachedInCompactHeight
sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}
if presentedViewController == nil{
present(hostingController, animated: true, completion: nil)
}
}
/// To compensate for orientation as of 13 Beta 4 only [.large()] works for landscape
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
isLandscape = true
self.presentedViewController?.popoverPresentationController?.adaptiveSheetPresentationController.detents = [.large()]
} else {
isLandscape = false
self.presentedViewController?.popoverPresentationController?.adaptiveSheetPresentationController.detents = detents
}
}
}
@available(iOS 15.0, *)
struct CustomSheetView_Previews: PreviewProvider {
static var previews: some View {
CustomSheetParentView()
}
}
iOS 16 베타
iOS 16 베타 애플은 순수한 스위프트를 제공합니다.하프모달용 UI 솔루션입니다.
.sheet(isPresented: $showSettings) {
SettingsView()
.presentationDetents:(
[.medium, .large],
selection: $settingsDetent
)
}
사용자 정의 멈춤쇠를 추가하고 백분율을 지정할 수도 있습니다.
static func custom<D>(D.Type) -> PresentationDetent
//A custom detent with a calculated height.
static func fraction(CGFloat) -> PresentationDetent
//A custom detent with the specified fractional height.
static func height(CGFloat) -> PresentationDetent
//A custom detent with the specified height.
예:
extension PresentationDetent {
static let bar = Self.fraction(0.2)
}
.sheet(isPresented: $showSettings) {
SettingsView()
.presentationDetents:([.bar])
}
하프 모달 시트를 사용할 수 있는 커스텀 수식어가 포함된 스위프트 패키지를 작성했습니다.
링크는 다음과 같습니다. https://github.com/AndreaMiotto/PartialSheet
자유롭게 사용하거나 기여할 수 있습니다.
iOS 16+
iOS 16에서 드디어 하프시트가 지원되는 것 같습니다.
는 사할수있시크관리기를 사용할 수 .PresentationDetent
구체적으로 으로적체.presentationDetents(_:selection:)
다음은 설명서의 예입니다.
struct ContentView: View {
@State private var showSettings = false
@State private var settingsDetent = PresentationDetent.medium
var body: some View {
Button("View Settings") {
showSettings = true
}
.sheet(isPresented: $showSettings) {
SettingsView()
.presentationDetents(
[.medium, .large],
selection: $settingsDetent
)
}
}
}
멈춤쇠를 하나 이상 제공하면 사람들이 시트를 끌어서 크기를 조정할 수 있습니다.
Presentation Dentent의 가능한 값은 다음과 같습니다.
large
medium
fraction(CGFloat)
height(CGFloat)
custom<D>(D.Type)
직접 만들어 zstack 안에 넣을 수 있습니다. https://www.mozzafiller.com/posts/swiftui-slide-over-card-like-maps-stocks
struct SlideOverCard<Content: View> : View {
@GestureState private var dragState = DragState.inactive
@State var position = CardPosition.top
var content: () -> Content
var body: some View {
let drag = DragGesture()
.updating($dragState) { drag, state, transaction in
state = .dragging(translation: drag.translation)
}
.onEnded(onDragEnded)
return Group {
Handle()
self.content()
}
.frame(height: UIScreen.main.bounds.height)
.background(Color.white)
.cornerRadius(10.0)
.shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
.offset(y: self.position.rawValue + self.dragState.translation.height)
.animation(self.dragState.isDragging ? nil : .spring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
.gesture(drag)
}
private func onDragEnded(drag: DragGesture.Value) {
let verticalDirection = drag.predictedEndLocation.y - drag.location.y
let cardTopEdgeLocation = self.position.rawValue + drag.translation.height
let positionAbove: CardPosition
let positionBelow: CardPosition
let closestPosition: CardPosition
if cardTopEdgeLocation <= CardPosition.middle.rawValue {
positionAbove = .top
positionBelow = .middle
} else {
positionAbove = .middle
positionBelow = .bottom
}
if (cardTopEdgeLocation - positionAbove.rawValue) < (positionBelow.rawValue - cardTopEdgeLocation) {
closestPosition = positionAbove
} else {
closestPosition = positionBelow
}
if verticalDirection > 0 {
self.position = positionBelow
} else if verticalDirection < 0 {
self.position = positionAbove
} else {
self.position = closestPosition
}
}
}
enum CardPosition: CGFloat {
case top = 100
case middle = 500
case bottom = 850
}
enum DragState {
case inactive
case dragging(translation: CGSize)
var translation: CGSize {
switch self {
case .inactive:
return .zero
case .dragging(let translation):
return translation
}
}
var isDragging: Bool {
switch self {
case .inactive:
return false
case .dragging:
return true
}
}
}
여기 내용에 맞게 확장할 수 있는 제 순진한 바닥 시트가 있습니다.끌지 않고 필요하면 비교적 쉽게 추가할 수 있어야 합니다 :)
struct BottomSheet<SheetContent: View>: ViewModifier {
@Binding var isPresented: Bool
let sheetContent: () -> SheetContent
func body(content: Content) -> some View {
ZStack {
content
if isPresented {
VStack {
Spacer()
VStack {
HStack {
Spacer()
Button(action: {
withAnimation(.easeInOut) {
self.isPresented = false
}
}) {
Text("done")
.padding(.top, 5)
}
}
sheetContent()
}
.padding()
}
.zIndex(.infinity)
.transition(.move(edge: .bottom))
.edgesIgnoringSafeArea(.bottom)
}
}
}
}
extension View {
func customBottomSheet<SheetContent: View>(
isPresented: Binding<Bool>,
sheetContent: @escaping () -> SheetContent
) -> some View {
self.modifier(BottomSheet(isPresented: isPresented, sheetContent: sheetContent))
}
}
다음과 같이 사용합니다.
.customBottomSheet(isPresented: $isPickerPresented) {
DatePicker(
"time",
selection: self.$time,
displayedComponents: .hourAndMinute
)
.labelsHidden()
}
베타 2 베타 3부터는 모달을 제시할 수 없습니다.View
~하듯이.fullScreen
다음과 같이 표시됩니다..automatic -> .pageSheet
하지만 일단 그것이 고쳐지더라도, 저는 그들이 당신에게 무료로 드래그 기능을 제공할 것인지에 대해 매우 의심스럽습니다.그것은 이미 문서에 포함되어 있을 것입니다.
이 답변을 사용하여 현재 전체 화면을 표시할 수 있습니다.여기 요지.
프레젠테이션 후에, 이것은 상호 작용을 어떻게 재현할 수 있는지에 대한 빠르고 더러운 예입니다.
@State var drag: CGFloat = 0.0
var body: some View {
ZStack(alignment: .bottom) {
Spacer() // Use the full space
Color.red
.frame(maxHeight: 300 + self.drag) // Whatever minimum height you want, plus the drag offset
.gesture(
DragGesture(coordinateSpace: .global) // if you use .local the frame will jump around
.onChanged({ (value) in
self.drag = max(0, -value.translation.height)
})
)
}
}
나는 스위프트를 썼습니다.하프 모달과 같은 커스텀 iOS 13과 버튼을 포함하는 UI 패키지.
GitHub repo: https://github.com/ViktorMaric/HalfModal
나는 스위프트에서 무엇이든 쓰는 거의 모든 iOS 개발자들이UI는 이 문제에 대처해야 합니다.물론 그랬지만, 여기 있는 대부분의 대답은 너무 복잡하거나 제가 원하는 것을 제공하지 못했다고 생각했습니다.
나는 GitHub에 있는 매우 간단한 부분 시트를 작성했고, 스위프트 패키지로 이용할 수 있습니다 - 절반.시트
아마도 다른 솔루션들과 비슷한 기능은 없지만 필요한 기능을 수행합니다.게다가, 자신의 글을 쓰는 것은 무슨 일이 일어나고 있는지 이해하는 데 항상 좋습니다.
참고 - 몇 가지 사항 - 우선, 이것은 매우 진행 중인 작업이므로, 언제든지 개선하십시오.둘째로, 당신이 Swift를 위해 개발하는 것처럼 일부러 .Podspec을 하지 않았습니다.UI는 iOS 13을 최소로 사용하고 있고, Swift Packages는 제 생각에 훨씬 더 좋습니다.
Andre Carrera의 답변은 훌륭하며 그가 제공한 이 가이드를 언제든지 사용하십시오. https://www.mozzafiller.com/posts/swiftui-slide-over-card-like-maps-stocks
SlideOverCard 구조를 수정하여 실제 장치 높이를 사용하여 카드가 멈출 위치를 측정합니다(경계를 가지고 놀 수 있습니다).필요에 따라 조정할 수 있는 높이):
struct SlideOverCard<Content: View>: View {
var bounds = UIScreen.main.bounds
@GestureState private var dragState = DragState.inactive
@State var position = UIScreen.main.bounds.height/2
var content: () -> Content
var body: some View {
let drag = DragGesture()
.updating($dragState) { drag, state, transaction in
state = .dragging(translation: drag.translation)
}
.onEnded(onDragEnded)
return Group {
Handle()
self.content()
}
.frame(height: UIScreen.main.bounds.height)
.background(Color.white)
.cornerRadius(10.0)
.shadow(color: Color(.sRGBLinear, white: 0, opacity: 0.13), radius: 10.0)
.offset(y: self.position + self.dragState.translation.height)
.animation(self.dragState.isDragging ? nil : .interpolatingSpring(stiffness: 300.0, damping: 30.0, initialVelocity: 10.0))
.gesture(drag)
}
private func onDragEnded(drag: DragGesture.Value) {
let verticalDirection = drag.predictedEndLocation.y - drag.location.y
let cardTopEdgeLocation = self.position + drag.translation.height
let positionAbove: CGFloat
let positionBelow: CGFloat
let closestPosition: CGFloat
if cardTopEdgeLocation <= bounds.height/2 {
positionAbove = bounds.height/7
positionBelow = bounds.height/2
} else {
positionAbove = bounds.height/2
positionBelow = bounds.height - (bounds.height/9)
}
if (cardTopEdgeLocation - positionAbove) < (positionBelow - cardTopEdgeLocation) {
closestPosition = positionAbove
} else {
closestPosition = positionBelow
}
if verticalDirection > 0 {
self.position = positionBelow
} else if verticalDirection < 0 {
self.position = positionAbove
} else {
self.position = closestPosition
}
}
}
enum DragState {
case inactive
case dragging(translation: CGSize)
var translation: CGSize {
switch self {
case .inactive:
return .zero
case .dragging(let translation):
return translation
}
}
var isDragging: Bool {
switch self {
case .inactive:
return false
case .dragging:
return true
}
}
}
22
이 튜토리얼을 사용하여 02:40분에 하프 모달이나 작은 모달을 만들 수 있습니다. 복잡한 코드를 사용하지 않고 모달의 크기를 조정하는 것은 인상적인 방법 중 하나입니다.발표에 신경 쓰는 것 뿐입니다.
사용법을 살펴봅시다.
.sheet(isPresented : yourbooleanvalue) {
//place some content inside
Text("test")
.presentationDetents([.medium,.large])
}
이 방법으로 시작할 때 중간일 수 있고 위로 끌어 올려 크게 만들 수 있는 모달을 설정합니다.그러나 이 차원 배열 내부에 .small 속성을 사용할 수도 있습니다.저는 그것이 가장 짧은 길이었고 가장 유용한 친근감이었다고 생각합니다.이 방법으로 수천 줄의 코드로부터 생명을 구했습니다.
여기서 요청한 것과 동일한 작업을 수행하려고 했습니다. Swift에서 기본적인 방식으로 공유 시트를 표시합니다.구성 요소를 구현/가져올 필요가 없는 UI.https://jeevatamil.medium.com/how-to-create-share-sheet-uiactivityviewcontroller-in-swiftui-cef64b26f073 에서 이 솔루션을 찾았습니다.
struct ShareSheetView: View {
var body: some View {
Button(action: actionSheet) {
Image(systemName: "square.and.arrow.up")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 36, height: 36)
}
}
func actionSheet() {
guard let data = URL(string: "https://www.zoho.com") else { return }
let av = UIActivityViewController(activityItems: [data], applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
}
}
내 작품:
var body: some View {
ZStack {
YOURTOPVIEW()
VStack {
Spacer()
.frame(minWidth: .zero,
maxWidth: .infinity,
minHeight: .zero,
maxHeight: .infinity,
alignment: .top)
YOURBOTTOMVIEW()
.frame(minWidth: .zero,
maxWidth: .infinity,
minHeight: .zero,
maxHeight: .infinity,
alignment: .bottom)
}
}
}
5, 12는 iOS 14, Swift 5, Xcode 12.5를 을 꽤 할 수 .UIActivityViewController
다른 보기 컨트롤러에 있습니다.보기 계층을 검사하거나 타사 라이브러리를 사용할 필요가 없습니다.유일한 해킹 부분은 보기 컨트롤러를 비동기식으로 표시하는 것인데, 이는 필요하지 않을 수도 있습니다.를 더 많이 가진 ㅠㅠㅠㅠㅠㅠㅠUI 환경은 개선을 위한 제안을 제공할 수 있습니다.
import Foundation
import SwiftUI
import UIKit
struct ActivityViewController: UIViewControllerRepresentable {
@Binding var shareURL: URL?
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> some UIViewController {
let containerViewController = UIViewController()
return containerViewController
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
guard let shareURL = shareURL, context.coordinator.presented == false else { return }
context.coordinator.presented = true
let activityViewController = UIActivityViewController(activityItems: [shareURL], applicationActivities: nil)
activityViewController.completionWithItemsHandler = { activity, completed, returnedItems, activityError in
self.shareURL = nil
context.coordinator.presented = false
if completed {
// ...
} else {
// ...
}
}
// Executing this asynchronously might not be necessary but some of my tests
// failed because the view wasn't yet in the view hierarchy on the first pass of updateUIViewController
//
// There might be a better way to test for that condition in the guard statement and execute this
// synchronously if we can be be sure updateUIViewController is invoked at least once after the view is added
DispatchQueue.main.asyncAfter(deadline: .now()) {
uiViewController.present(activityViewController, animated: true)
}
}
class Coordinator: NSObject {
let parent: ActivityViewController
var presented: Bool = false
init(_ parent: ActivityViewController) {
self.parent = parent
}
}
}
struct ContentView: View {
@State var shareURL: URL? = nil
var body: some View {
ZStack {
Button(action: { shareURL = URL(string: "https://apple.com") }) {
Text("Share")
.foregroundColor(.white)
.padding()
}
.background(Color.blue)
if shareURL != nil {
ActivityViewController(shareURL: $shareURL)
}
}
.frame(width: 375, height: 812)
}
}
보다 일반적인 솔루션을 위해 다음과 같은 아이디어를 생각해 냈습니다. https://github.com/mtzaquia/UIKitPresentationModifier
이것은 당신이 사용할 수 있는 일반적인 수식어입니다.UIKit
내의 프레젠테이션SwiftUI
보다.
거기서부터 세상은 당신의 굴입니다.유일한 단점은 사용자 지정 환경 값을 표시 보기에서 표시 보기로 캐스케이드해야 할 수 있다는 것입니다.
myPresentingView
.presentation(isPresented: $isPresented) {
MyPresentedView()
} controllerProvider: { content in
let controller = UIHostingController(rootView: content)
if #available(iOS 15, *) {
if let sheet = controller.sheetPresentationController {
sheet.preferredCornerRadius = 12
sheet.prefersGrabberVisible = true
}
}
return controller
}
언급URL : https://stackoverflow.com/questions/56700752/swiftui-half-modal
'programing' 카테고리의 다른 글
JSON을 POST할 때 CORS가 활성화되었지만 사전 비행에 대한 응답에 잘못된 HTTP 상태 코드 404가 있습니다. (0) | 2023.08.19 |
---|---|
#1054 - 알 수 없는 열 - 백택스 문제 (0) | 2023.08.19 |
새 JSON 데이터로 데이터 테이블을 수동으로 업데이트하는 방법 (0) | 2023.08.19 |
numpy의 내부 정밀도는 얼마입니까?float128? (0) | 2023.08.19 |
매개 변수가 있는 저장 프로시저 (0) | 2023.08.14 |