feed
2023年06月19日, 編集履歴
Mailto Interceptor ver. 1.4をリリースしました。
mailto:
リンクのクリック等によるメールアプリケーションの意図しない即時起動を抑制できるmacOSアプリケーションです。デフォルトのメールアプリケーションとしてMailto Interceptorを指定することで、mailto:
リンクのクリック等があったときに、
何もしない
メールアドレスをコピー
URLを開く(ウェブメールの作成画面等)
動作を選択できるポップアップメニューを表示させる
といった動作をさせることができます。
ver. 1.4では、
「動作を通知」機能をシステム標準の通知センターを使うように変更
コードの近代化改修
を行いました。
今となってはmailto:
リンクを見ることも少なくなってはきましたが、どうぞよろしくお願いします。
2023年03月18日, 編集履歴
いつの頃からかは解らないが、少なくともmacOS 13.2.1のSwiftUIでは.opacity()
と.onHover()
の順番が重要になっている。
環境:
macOS 13.2.1
Xcode 14.2 (14C18)
以下のようなSwiftUIビューがあったとする。
struct ContentView : View {
@State private var isOn = false
var body : some View {
Toggle ( "Toggle" , isOn : $ isOn )
. toggleStyle ( . switch )
. onHover { isHovering in
print ( isHovering )
}
. padding ()
}
}
Toggle
スウィッチの領域にマウスポインタを持っていく(ホバーする)と、.onHover()
が反応する。ここで.opacity()
を付けてToggle
に透明度を設定したいとする。
struct ContentView : View {
@State private var isOn = false
var body : some View {
Toggle ( "Toggle" , isOn : $ isOn )
. toggleStyle ( . switch )
. onHover { isHovering in
print ( isHovering )
}
. opacity ( 0.0 )
. padding ()
}
}
.onHover()
の後ろに.opacity()
を付与した場合、macOS 11では完全に透明にしても.onHover()
は反応していたが、macOS 13では反応しなくなっていた。完全に透明にしたのがいけなかったのかと思い、.opacity(0.5)
とかしてみると反応してくれる。なるほど。では、.opacity(0.3)
なら? なぜか「Toggle」と書かれたラベル部分にマウスを乗せても反応せず、スウィッチ部分に乗せた場合にだけ反応する。.onHover()
が反応する領域が変化するという変な挙動を示す。
struct ContentView : View {
@State private var isOn = false
var body : some View {
Toggle ( "Toggle" , isOn : $ isOn )
. toggleStyle ( . switch )
. opacity ( 0.0 )
. onHover { isHovering in
print ( isHovering )
}
. padding ()
}
}
のように.opacity()
を先に記述すると、完全に透明にした場合でも.onHover()
が反応するし、ラベル部分であってもちゃんと反応領域に含まれる。
というわけで、(少なくともmacOS 13.2.1では).opacity()
が先、.onHover()
が後という順番でないといけない。
2023年03月14日, 編集履歴
現在使用しているMacはMacBook Pro 15インチの2018年モデルで、これは悪名高きバタフライキーボードが採用されているものだ。曰く、打ち心地が悪い、不具合が発生しやすいといった声が聞こえてきていた。私自身は打ち心地は問題がなく、これまで不具合も出ていなかった。しかし使い始めて約5年、とうとう意図しない反復入力されてしまう不具合が発生するようになった。
バタフライキーボードの不具合に関してはAppleの無償修理プログラムがあるのだが、対象となるのが販売日より4年間ということで、ちょうど保証期間が切れた直後という間の悪さ。まだまだこのMacBook Proを使い続けたい意志はあるものの、他にバッテリーの状態も悪く、それらが同時に修理対象となると、費用が数万円かかることが予想される。それだけ出して有償修理するくらいなら新しいAppleシリコンMacが欲しいけれど、それこそ数十万円が必要になってくる。
そこで外付けキーボードを用意することにした。メルカリでAppleのMagic Keyboardがリーズナブルな金額で手に入ったので、それをMacBook Proのキーボード面に乗せるスタイルで運用する。問題になるのは、上に載せたMagic KeyboardによってMacBook Pro本体のキーボードが押されてしまうことである。
この問題を解消するために「キーボードブリッジ」という製品がある。ノートパソコンのキーボード面を覆うためのプレート状の製品である。そのプレートの上に外付けキーボードを置くという寸法である。バード電子というメーカから5,000円程度で販売されている。
ただ、結局のところ、板状のものでキーボード面を覆えれば良いわけである。ということで、
Amazonの梱包の中敷に使われていた薄い段ボール板を半分に切って、ダイソーで買ってきた滑り止めのゴム足を貼り付けたものをMacBook Proに乗せてみた。こんなものでもちゃんとキーボードブリッジとして機能している。名付けて「貧者のキーボードブリッジ」である。
ゴム足をつけているとはいえ、ほぼほぼMacBook Proのキーボード面に密着してしまっているので、放熱面では問題がある。強度面との兼ね合いがあるが、段ボールに穴を開けてしまってもいいかもしれない。
機能確認はできたので、改めて本家バード電子のキーボードブリッジの購入を考えるか、あるいは、アクリル板のサイズや加工方法を指定してお安く購入できるネットショップがあるようなので、そこで注文してみるのもいいかもしれない。
最後に、いちばんの問題はTouch IDが塞がれてしまったことである。購入したMagic KeyboardはTouch IDが付いていないタイプ。Touch ID付きのMagic Keyboardについては、Touch ID機能はIntel Macでは動作しないようなのでどうしようもない。Touch IDが使いたい時はキーボードブリッジをずらすしかない。
2022年11月03日, 編集履歴
macOSのメニューバーエクストラは、画面最上部のメニューバー右側に配置されるアイコンであり、それをクリックする事でメニューあるいはポップオーバーを表示し、アプリ等が最前面になくとも機能を呼び出せるUIである。常駐アプリ等で設定変更や状態確認のために使われることが多い。
SwiftUI macOSアプリでメニューバーアイコンを出すにはMenuBarExtra
を使う。
文字列表示
メニューバーエクストラに文字列として項目を表示したい場合は、
@main
struct MenuBarExtraSampleApp : App {
var body : some Scene {
MenuBarExtra ( "MenuBarExtra" ) {
Button ( "About App" ) {
NSApp . orderFrontStandardAboutPanel ( nil )
NSApp . activate ( ignoringOtherApps : true )
}
Button ( "Settings..." ) {
NSApp . sendAction ( Selector (( "showSettingsWindow:" )), to : nil , from : nil )
NSApp . activate ( ignoringOtherApps : true )
}
Divider ()
Button ( "Quit App" ) {
NSApp . terminate ( nil )
}
}
}
}
のようにする。この例ではメニュー形式のメニューバーエクストラが作られる。
アイコン表示
アイコンを表示する場合は、
MenuBarExtra ( "MenuBarExtra" , image : "icon" ) {
...
}
や、
MenuBarExtra ( "MenuBarExtra" , systemImage : "star.fill" ) {
...
}
とする。このとき、第一引数の文字列は表示されなくなる。
アイコンと文字列表示
アイコンも文字列も両方出したい場合は、
MenuBarExtra {
...
} label : {
Label ( "MenuBarExtra" , systemImage : "star.fill" )
. labelStyle ( . titleAndIcon )
}
とする。ここで単にLabel
だけだとやはり文字列が表示されない。.labelStyle(.titleAndIcon)
を指定することでアイコンと文字列両方が表示される。
ポップオーバー表示
通常はメニュー形式で表示されるメニューバーエクストラだが、ポップオーバー形式にすることもできる。その場合は、
MenuBarExtra ( "MenuBarExtra" ) {
HStack {
Image ( systemName : "heart.fill" )
Button ( "MenuBarExtra" ) {}
Image ( systemName : "heart.fill" )
}
. frame ( width : 300 , height : 200 )
}
. menuBarExtraStyle ( . window )
のようにmenuBarExtraStyle
を使う。
メニューバーエクストラの表示・非表示切り替え
メニューバーエクストラの表示・非表示の切り替えをしたい場合はisInserted
が入っているイニシャライザを使う。
@main
struct StatusBarSampleApp : App {
@AppStorage ( "MenuBarExtraShown" ) private var menuBarExtraShown = true
var body : some Scene {
MenuBarExtra ( "MenuBarExtra" , systemImage : "star.fill" , isInserted : $ menuBarExtraShown ) {
...
}
}
}
この場合、どこかのビューで、
struct GeneralSettingsView : View {
@AppStorage ( "MenuBarExtraShown" ) private var menuBarExtraShown : Bool = true
var body : some View {
Form {
Toggle ( "Menu Bar Extra" , isOn : $ menuBarExtraShown )
}
. padding ()
}
}
のように切り替えをするUIを用意する。
常駐アプリ化
メインウィンドウを持たずにメニューバーエクストラを操作の起点とするような常駐アプリにしたい場合は、ターゲットの「Info」欄で「Application is agent (UIElement)」を「YES」にする。こうすることで、アプリがDockやAppスイッチャーに表示されなくなる。
2022年10月31日, 編集履歴
SwiftUI macOSアプリで、以下のような設定ウィンドウを作りたいとする。
ラベルは右揃えで、ポップアップメニューやテキストフィールド等の操作部品は左揃えにして整列させたい。VStack
や単純なForm
ではきれいな整列ができない(……ことはないがややこしい黒魔術が必要となる)。よくあるパターンのレイアウトなのに変な感じだった。
そんな中、macOS 13.0から使える新しいLabeledContent
をForm
と組み合わせることで、かんたんにきれいな整列が実現できるようになった。
環境は以下の通り。
macOS 13.0
Xcode 14.1 RC2
macOS 13.0 SDK
まずはこれまでの状態を確認してみる。UIを縦に並べていく場合、VStack
やForm
を使う。VStack
では単純な左揃えや中央揃え等になってしまうので却下。こういった設定項目を縦に並べる場合はForm
を使う。たとえば以下のような感じ。
Form {
Picker ( "Pref 1:" , selection : . constant ( 1 )) {
Text ( "Option 1" ) . tag ( 1 )
Text ( "Option 2" ) . tag ( 2 )
}
. fixedSize ()
TextField ( "Preference 2:" , text : . constant ( "" ))
. frame ( width : 200 )
HStack {
Text ( "Long Preference 3:" )
Toggle ( "Enabled Hoge" , isOn : . constant ( true ))
}
HStack {
Text ( "Pref 4:" )
Button ( "Button" ) { }
}
}
. padding ()
このとき、Picker
やTextField
など、標準で左側にラベル的要素を持つUIは意図通りきれいに整列される。しかし、左側にラベル的要素を持たないToggle
やButton
などは、ラベル的要素を表現するためにHStack
と組み合わせる必要があり、その場合、意図通りには整列されない。
macOS 12までは、Example of aligning labels in SwiftUI.Form on macOS にあるような.alignmentGuide
を使うややこしい黒魔術的な手法で整列させなければならなかった。
LabeledContent
の場合
macOS 13.0からLabeledContent
が使えるようになった。これは前述のToggle
やButton
等の、標準では左側にラベル的要素を持たないUI部品にラベルを付与できるようになる。そして、それをForm
と組み合わせることできれいな整列をかんたんに実現できる。こんな感じ。
Form {
Picker ( "Pref 1:" , selection : . constant ( 1 )) {
Text ( "Option 1" ) . tag ( 1 )
Text ( "Option 2" ) . tag ( 2 )
}
. fixedSize ()
TextField ( "Preference 2:" , text : . constant ( "" ))
. frame ( width : 300 )
LabeledContent ( "Long Preference 3:" ) {
Toggle ( "Enabled Hoge" , isOn : . constant ( true ))
}
LabeledContent ( "Pref 4:" ) {
Button ( "Button" ) {}
}
}
. padding ()
前項のコード例と違うのは、Toggle
とButton
の部分でHStack
の代わりにLabeledContent
を使ってラベルを持たせている点。
特に黒魔術は必要なく、素直に意図通りのレイアウトが実現できる。SwiftUIもだんだん良くなってきた!
macOS 13.0 VenturaからはForm
に対して.formStyle()
で表示形式を変更できるようになった。
Form {
Picker ( "Pref 1" , selection : . constant ( 1 )) {
Text ( "Option 1" ) . tag ( 1 )
Text ( "Option 2" ) . tag ( 2 )
}
TextField ( "Preference 2" , text : . constant ( "" ))
Toggle ( "Long Long Preference 3" , isOn : . constant ( true ))
HStack {
Text ( "Pref 4" )
Spacer ()
Button ( "Button" ) { }
}
LabeledContent ( "Pref 5" ) {
Button ( "Button" ) { }
}
}
. formStyle ( . grouped )
このように.formStyle(.grouped)
を指定することで、Venturaの新しいシステム設定のような表示形式にできる。
この場合、Toggle
は前述のLabeledContent
を使わずとも自然に記述できる。Button
に関してはHStack
でラベル的要素を付けて整列できるが、LabeledContent
を使った方が自然な記述ができる。