単一カードビューの設計
Designing a single card view
flashcards(要調査!!)
このプロジェクトでは、ユーザーに「スコットランドの首都は何ですか?」など、知りたいことについてのプロンプトテキストが付いたカードを表示し、タップすると答えが表示されます。この場合はもちろんエジンバラです。
ほとんどのプロジェクトで開始する賢明な場所は、使用するデータモデルを定義することです。
Portrait, Landscape Left, and Landscape Right(横表示)
(「PROJECT」「TARGET」)
デフォルト値は、ポートレート、ランドスケープレフト、ランドスケープライトをチェックすることですが、ポートレートのチェックを外して、2つのランドスケープの向きのみがサポートされるようにしてください。
450の幅は偶然ではありません。最小のiPhoneの横幅は480ポイントであるため、このカードはすべてのデバイスで完全に表示されます。
// // Card.swift // Flashzilla import Foundation struct Card { let prompt: String let answer: String static var example: Card { Card(prompt: "Who played the 13th Doctor in Doctor Who?", answer: "Jodie Whittaker") } }
// // CardView.swift // Flashzilla import SwiftUI struct CardView: View { @State private var isShowingAnswer = false let card: Card var body: some View { ZStack { RoundedRectangle(cornerRadius: 25, style: .continuous) .fill(Color.white) .shadow(radius: 10) VStack { Text(card.prompt) .font(.largeTitle) .foregroundColor(.black) if isShowingAnswer { Text(card.answer) .font(.title) .foregroundColor(.gray) } } .padding(20) .multilineTextAlignment(.center) } .frame(width: 450, height: 250) .onTapGesture { self.isShowingAnswer.toggle() } } } struct CardView_Previews: PreviewProvider { static var previews: some View { CardView(card: Card.example) } }
// // ContentView.swift // Flashzilla import SwiftUI struct ContentView: View { var body: some View { CardView(card: Card.example) } }
カードのスタックを構築する
Building a stack of cards
Swiftの配列には便利な初期化子があります。初期化子init(repeating:count:)は1つの値を取り、それを何度も繰り返して配列を作成します。今回の例では、これを使用してCard簡単なテスト配列を作成できます。
@State private var cards = [Card](repeating: Card.example, count: 10)
SwiftUIコードを記述する最善の方法は、乱雑な計算を切り分けて、メソッドまたは修飾子として処理することです。今回は、はstacked()
// // ContentView.swift // Flashzilla import SwiftUI //------------- struct ContentView: View { @State private var cards = [Card](repeating: Card.example, count: 10) var body: some View { ZStack { Image("background") .resizable() .scaledToFill() .edgesIgnoringSafeArea(.all) VStack { ZStack { ForEach(0..<cards.count, id: \.self) { index in CardView(card: self.cards[index]) .stacked(at: index, in: self.cards.count) } } } } } } //------------- extension View { func stacked(at position: Int, in total: Int) -> some View { //let offset = CGFloat(total - position) //配列内の場所ごとにビューを10ポイント押し下げます(0、次に10、20、30など) // return self.offset(CGSize(width: 0, height: position * 10)) let offset = CGFloat(total - position) return self.offset(CGSize(width: 0, height: offset * 10)) } } //------------- struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
DragGestureとoffset()によるビューの移動
Moving views with DragGesture and offset()
DragGestureでCardView移動できるようにします。
ジェスチャーによって生成された値を使用して、ビューの不透明度と回転を制御します。
移動と回転に関しては、ビューを回転させながら、ビューを真の西に(その回転に関係なく)直接スライドさせる場合は、最初に回転を配置し、次にオフセットを配置する必要があります。
3つの修飾子
rotationEffect
offset
opacity
// // ContentView.swift // Flashzilla import SwiftUI //------------- struct ContentView: View { @State private var cards = [Card](repeating: Card.example, count: 10) func removeCard(at index: Int) { cards.remove(at: index) } var body: some View { ZStack { Image("background") .resizable() .scaledToFill() .edgesIgnoringSafeArea(.all) VStack { ZStack { ForEach(0..<cards.count, id: \.self) { index in CardView(card: self.cards[index]) { withAnimation { self.removeCard(at: index) } } .stacked(at: index, in: self.cards.count) } } } } } } //------------- extension View { func stacked(at position: Int, in total: Int) -> some View { //let offset = CGFloat(total - position) //配列内の場所ごとにビューを10ポイント押し下げます(0、次に10、20、30など) // return self.offset(CGSize(width: 0, height: position * 10)) let offset = CGFloat(total - position) return se lf.offset(CGSize(width: 0, height: offset * 10)) } } //-------------
// // CardView.swift // Flashzilla // // Created by Naoki Abe on 2020/09/09. // Copyright © 2020 Naoki Abe. All rights reserved. // import SwiftUI struct CardView: View { @State private var isShowingAnswer = false @State private var offset = CGSize.zero let card: Card var removal: (() -> Void)? = nil var body: some View { ZStack { RoundedRectangle(cornerRadius: 25, style: .continuous) .fill(Color.white) .shadow(radius: 10) VStack { Text(card.prompt) .font(.largeTitle) .foregroundColor(.black) if isShowingAnswer { Text(card.answer) .font(.title) .foregroundColor(.gray) } } .padding(20) .multilineTextAlignment(.center) } .frame(width: 450, height: 250) .rotationEffect(.degrees(Double(offset.width / 5))) .offset(x: offset.width * 5, y: 0) .opacity(2 - Double(abs(offset.width / 50))) .gesture( DragGesture() .onChanged { gesture in self.offset = gesture.translation } .onEnded { _ in if abs(self.offset.width) > 100 { // remove the card self.removal?() } else { self.offset = .zero } } ) .onTapGesture { self.isShowingAnswer.toggle() } } } struct CardView_Previews: PreviewProvider { static var previews: some View { CardView(card: Card.example) } }