Skip to content

Instantly share code, notes, and snippets.

@HironobuIga
Last active December 21, 2022 14:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save HironobuIga/1abd6e38fddc5d06f1e7be5a49208704 to your computer and use it in GitHub Desktop.
Save HironobuIga/1abd6e38fddc5d06f1e7be5a49208704 to your computer and use it in GitHub Desktop.
Chat Screen
import SwiftUI
struct Sample: Identifiable {
let id: String
var num: Int
let date: Date
var title: String { "title \(num)" }
var content: String { "content \(num)" }
init(num: Int) {
self.id = UUID().uuidString
self.num = num
self.date = .now
}
}
struct HeightKey: PreferenceKey {
typealias Value = CGFloat
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value += nextValue()
}
}
@MainActor
final class SampleViewModel: ObservableObject {
@Published var list: [Sample] = .init()
func didTapAddButton() {
list.insert(Sample(num: list.endIndex + 1), at: 0)
}
func didTapRemoveButton() {
guard list.count > 0 else { return }
list.remove(at: 0)
}
}
struct SampleScreen: View {
@StateObject private var viewModel: SampleViewModel = .init()
@State var height: CGFloat = 0
let formatter = ISO8601DateFormatter()
var body: some View {
VStack(spacing: 0) {
list()
HStack {
Button {
viewModel.didTapAddButton()
} label: {
Text("追加")
}
Button {
viewModel.didTapRemoveButton()
} label: {
Text("削除")
}
}
}
.navigationTitle("List")
.navigationBarTitleDisplayMode(.inline)
}
func list() -> some View {
GeometryReader { scrollViewProxy in
ScrollView {
// 要素数が少ない場合に要素を上詰めするために画面下部にスペースを確保する
// 他の要素で画面全体のスペースが埋まる場合は不要なので、高さを0とする
Spacer()
.frame(height: max(scrollViewProxy.size.height - height, 0))
LazyVStack(alignment: .leading, spacing: 0) {
ForEach(viewModel.list) { sample in
cell(sample: sample)
.rotation3DEffect(.degrees(180), axis: (x: 1, y: 0, z: 0))
}
}
.overlay {
GeometryReader { contentsProxy in
// PreferenceKeyを使用しコンテンツの高さを伝える
Color.clear.preference(
key: HeightKey.self,
value: contentsProxy.size.height
)
}
}
}
.rotation3DEffect(.degrees(180), axis: (x: 1, y: 0, z: 0))
.onPreferenceChange(HeightKey.self) { newHeight in
// コンテンツの高さの変化を検知し、\@Stateで保持している
// heightに伝えViewに反映させる
height = newHeight
}
}
}
func cell(sample: Sample) -> some View {
VStack(alignment: .leading) {
Text(sample.title)
Text(sample.content)
Text(formatter.string(from: sample.date))
}
.padding(.horizontal, 16)
.padding(.vertical, 8)
}
}
struct SampleScreen_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
SampleScreen()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment