1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SwiftUIでリストの並び替えをする方法

Posted at

つまづいたこと

  • リストの並び替えができなかった
  • プレビューではonMove自体が動作しなかった
  • シミュレーターではonMove自体は動作したが、並び替えができなかった

環境

  • Xcode 15.4
  • iOS17.5
  • SwiftUI
  • CoreData

条件

解決方法

  • プレビューではonMoveが動作しないので、シミュレーターで確認した
  • @Queryの後に(sort: [SortDescriptor(\Memo.order)])をつけると並び替えができるようになった

知見

  • プレビューは完全ではないのでちゃんと検証したいときはシミュレーターで確認する
  • moveMemo()でorderプロパティを更新していたが、DBから@Queryで取得されたデータはそのままの順番で使用されるのでorderの順番がUIに反映されていなかった
  • (sort: [SortDescriptor(\Memo.order)])を追加することで、orderプロパティの順番でソートされた状態で取得される

ソース


import SwiftUI
import SwiftData
import Algorithms
import Foundation

@Model
final class Memo {
    var id: String
    var order: Int
    var content: String

    init(content: String, order: Int = 0) {
        self.id = ""
        self.content = content
        self.order = order // 初期値として0を設定

    }
}

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query(sort: [SortDescriptor(\Memo.order)]) private var memos: [Memo]
    
    var body: some View {
        NavigationStack {
            List{
                ForEach(memos, id: \.self){ memo in
                    NavigationLink(memo.content, destination: MemoDetailView(memo: .constant(memo))
                    )
                }
                .onMove(perform: moveMemo)
            }
            .toolbar{
                ToolbarItem(placement: .navigationBarTrailing){
                    NavigationLink(destination:
                        MemoDetailView(memo:.constant(Memo(content: "")
                        )
                    )
                
                    ){
                        Image(systemName: "plus")
                    }

                }
                ToolbarItem(placement: .navigationBarTrailing) { // EditButtonをナビゲーションバーの左側に配置
                    EditButton()
                }
            }
        }
    }    

    private func moveMemo(from source: IndexSet, to destination: Int) {
        var orderedMemos = memos.sorted(by: { $0.order < $1.order }) // orderで並び替え
        // 並び替えを実行
        orderedMemos.move(fromOffsets: source, toOffset: destination)
        // 更新された順序をmodelContextに反映
        for (index, memo) in orderedMemos.enumerated() {
            if let existingMemo = memos.first(where: { $0.id == memo.id }) {
                existingMemo.order = index
            }
        }
        saveContext()
    }
    // コンテキストの保存を行う関数
    private func saveContext() {
        do {
            try modelContext.save()
        } catch {
            print("コンテキストの保存に失敗しました: \(error.localizedDescription)")
        }
    }
}


1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?