macOS   SwiftUIプログラミング   ドラッグで図形を移動する

ホーム

【お知らせ】
SwiftUIで作った macOS Todo アプリ ToDone を100ダウンロードまで無料にしました。マニュアルページは、ToDone サポートページ です。

【本文】
将来的には、ペイントを簡単にしたようなグラフィックエディターを作りたいのですが、そこには一気に進めないので、まずは図形をドラッグできるところまでをやってみようと思います。

このコーナーでは、任意のテキストエディタでコードを記述し、 ターミナルを使ってビルドする方法で作業を進めています。Xcode をお使いの場合は、Xcodeで作業する場合 をご一読ください。

なお、ターミナルを使う場合も、Swift コンパイラや SwiftUI フレームワークなどを Mac にインストールするために Xcode をインストールして、一度起動させなければなりません。インストールが終われば Xcode は終了しても大丈夫です。

また、作成したアプリケーションを App Storeに提出するためのファイルにするには、 Xcode を使わなければならなかったかもしれません。 どこかで Xcode を使わずに作る方法を見たような気もするのですが...

私の開発環境は次のとおりです。

  • MacBook Air 2018年モデル、メモリ8G
  • macOS Monterey 12.4
  • Xcode 13.4.1
  • Swift 5.6.1

Drag Gesture

ドラッグで図形を移動するには、DragGesture を使うのが良さそうです。まずは次のサンプルを土台にしてみます。
DragGesture | Apple Developer Documentation


App.swift

Xcode では、プロダクト名App.swift になります。コード内容は macOS 用に少し変更しています。


import SwiftUI

@main

struct FooApp: App {
    init() {
        // Tab(タブ)に関するメニューを削除するために次のコードを追加しました。
        NSWindow.allowsAutomaticWindowTabbing = false
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .commands(content: {
            // New Window メニューを削除するために次のコードを追加しました。
            CommandGroup(replacing: .newItem) {}
        })
    }
}
	


View.swift

Xcode では、ContentView.swift になります。コード内容は macOS 用に少し変更しています。


import SwiftUI
 
struct ContentView: View {
    @State var isDragging = false

    var drag: some Gesture {
        DragGesture()
            .onChanged { _ in self.isDragging = true }
            .onEnded { _ in self.isDragging = false }
    }

    var body: some View {
        VStack {
            Circle()
                .fill(self.isDragging ? Color.red : Color.blue)
                .frame(width: 100, height: 100, alignment: .center)
                .gesture(drag)
        }
        // macOS 用にウィンドウの大きさを設定しています。
        .frame(minWidth: 300, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
        // macOS 用にウィンドウを閉じるとアプリケーションも終了するようにしています
        .onDisappear(){ NSApplication.shared.terminate(self)}
    }
}
	


アプリケーションバンドル

Xcode で作業する場合は、この部分は無視してください。 ターミナルで作業する場合は「アイコン」を参考にしてアプリケーションバンドルを作ってください。 アプリケーションの名前を変えるために、Info.plist の CFBundleName を書き換えます。ここでは「Drag」という名前にしました。

アイコンは次のサイトから .icns ファイルをダウンロードしました。
フリーアイコンSVG、PNG、ICO、ICNS

Info.plist


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"https://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleExecutable</key>
	<string>foo</string>
	<key>CFBundleIconFile</key>
	<string>icon-macbook.icns</string>
	<key>CFBundleName</key>
	<string>Drag</string>
</dict>
</plist>
    


ビルド

Xcode で作業している場合は、▶︎(ビルドボタン)をクリックするか、⌘Rを押してください。ターミナルでビルドする場合は次のようにします。


swiftc App.swift View.swift -o foo
mv foo Foo.app/Contents/MacOS
    

実行

青い円をドラッグすると、移動はできませんが赤い色に変わります。マウスをリリース(ドロップ)すると青い色に戻ります。とりあえずドラッグとドロップのタイミングは感知できているみたいです。これを移動に変えれば良いわけですよねー。簡単にできるかな?

円を移動できるようにする

View.swift

Xcode では、ContentView.swift になります。App.swift(プロダクト名App.swift)は、前述と同じです。


import SwiftUI
 
struct ContentView: View {
    @State var isDragging = false
    @State var location = CGPoint(x: 150, y: 150)

    var drag: some Gesture {
        DragGesture()
            .onChanged { value in
                location = value.location
                self.isDragging = true
            }
            .onEnded { _ in self.isDragging = false }
    }

    var body: some View {
        VStack {
            Circle()
                .fill(self.isDragging ? Color.red : Color.blue)
                //.frame(width: 100, height: 100, alignment: .center)
                .frame(width: 100, height: 100)
                .position(location)
                .gesture(drag)
        }
        .frame(minWidth: 300, maxWidth: .infinity, minHeight: 300, maxHeight: .infinity)
        .onDisappear(){ NSApplication.shared.terminate(self)}
    }
}
    

コード説明

  1. @State var location = CGPoint(x: 150, y: 150)
    location(位置)用にプロパティを追加しています。location は図形の中心点の x y 値になります
  2. .onChanged { value in location = value.location ・・・}
    ドラッグ中、常に位置情報が更新されます
  3. .position(location)
    Circle の position モディファイアで円の位置が決まっています

ドラッグで円を移動できるようになりました。




27008 visits
Posted: Jul. 30, 2022
Update: Jul. 30, 2022

ホーム   目次