【Swift】UIToolbar 0->1
var toolbar: UIToolbar!
The custom toolbar associated with the navigation controller.
func setToolbarHidden(Bool, animated: Bool)
Changes the visibility of the navigation controller’s built-in toolbar.
var isToolbarHidden: Bool
A Boolean indicating whether the navigation controller’s built-in toolbar is visible.
class let hideShowBarDuration: CGFloat
This variable specifies the duration when animating the navigation bar. Note that this is a constant value, so it cannot be set.
UIViewController
setToolbarItems(_:animated:)
Sets the toolbar items to be displayed along with the view controller.
func setToolbarItems(_ toolbarItems: [UIBarButtonItem]?,
animated: Bool)
Parameters
toolbarItems
The toolbar items to display in a built-in toolbar.
animated
If true, animate the change of items in the toolbar.
ナビゲーションコントローラーによって管理されるビューコントローラーは、このメソッドを使用して、ナビゲーションコントローラーの組み込みツールバーのツールバー項目を指定できます。 ビューコントローラが表示される前、またはすでに表示された後に、ビューコントローラのツールバー項目を設定できます。
UIBarButtonItem
A specialized button for placement on a toolbar or tab bar.
class UIBarButtonItem : UIBarItem
通常、Interface Builderを使用して、バーボタンアイテムを作成および構成します。 ただし、セッターメッセージをUIBarButtonItemAppearanceに送信してすべてのボタンをカスタマイズするか、特定のUIBarButtonItemインスタンスに送信することで、ボタンの外観をカスタマイズできます。 UINavigationItemオブジェクト(backBarButtonItem、leftBarButtonItem、rightBarButtonItem)またはUIToolbarインスタンスの標準的な場所でカスタマイズされたボタンを使用できます。
一般に、カスタム値が設定されていない他の状態で使用できるように、通常の状態の値を指定する必要があります。 同様に、プロパティがバーのメトリックに依存している場合(たとえば、iPhoneの場合、横向きの場合、バーの高さは標準とは異なります)、UIBarMetrics.defaultの値を指定する必要があります。
外観と動作の構成の詳細については、ツールバーを参照してください。
init(image: UIImage?, style: UIBarButtonItem.Style, target: Any?, action: Selector?)
Initializes a new item using the specified image and other properties.
UIBarButtonItem.Style
enum Style : Int
case plain = 0
タップすると光ります。 デフォルトのアイテムスタイル。
case done = 2
完了ボタンのスタイル-たとえば、いくつかのタスクを完了して前のビューに戻るボタン。
func setBackgroundImage(UIImage?, for: UIControl.State, barMetrics: UIBarMetrics)
Sets the background image for a specified state and bar metrics.
※ボタンのバックグラウンドだからうまくいかない?
backgroundImage
The background image for the specified state and metrics.
state
A control state.
barMetrics
Bar metrics.
良い結果を得るには、backgroundImageはストレッチ可能な画像である必要があります。
UIBarMetrics
Constants to specify metrics to use for appearance.
enum UIBarMetrics : Int
case `default` = 0
case compact = 1
電話イディオムを使用するときのメトリックを指定します。
case defaultPrompt = 101
UINavigationBarやUISearchBarなどのpromptプロパティを持つバーのデバイスのデフォルトメトリックを指定します。
case compactPrompt = 102
UINavigationBarやUISearchBarなど、電話イディオムを使用するときに、promptプロパティを使用してバーのメトリックを指定します。
メトリック(英:metric)とは
ネットワークの世界における「目的地まで、あと○メートルです」のこと。行われる道案内(ルーティング)で使われる情報で、相手のところに辿り着くまでどれだけ大変かの指標
flexibleSpace()
Creates a new flexible width space item.
class func flexibleSpace() -> Self
柔軟な幅のスペースUIBarButtonItem。
これはiOS 14.0+
UIBarButtonItem.SystemItem
Defines system-supplied images for bar button items.
case flexibleSpace
Blank space to add between other items. The space is distributed equally between the other items. Other item properties are ignored when this value is set.
case fixedSpace
Blank space to add between other items. Only the width property is used when this value is set.
これでイケた
let spaceFlexToolbar = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceToolbar = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spaceToolbar.width = 200
ちょっと気になる
init(image: UIImage?, landscapeImagePhone: UIImage?, style: UIBarButtonItem.Style, target: Any?, action: Selector?)
Initializes a new item using the specified images and other properties.
Legacy Customizations
Customize appearance information directly on the navigation bar object.
iOS 13以降では、standardAppearance、compactAppearance、およびscrollEdgeAppearanceプロパティを使用してナビゲーションバーをカスタマイズします。 これらのレガシーアクセサーを引き続き使用して、ナビゲーションバーの外観を直接カスタマイズできますが、さまざまなバー構成の外観を自分で更新する必要があります。
func setBackgroundImage(UIImage?, for: UIBarPosition, barMetrics: UIBarMetrics)
Sets the background image to use for a given bar position and set of metrics.
最終的に使えそうなやつは
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = self.editButtonItem
self.navigationItem.rightBarButtonItem?.title = "選択"
let sendButton = UIBarButtonItem(barButtonSystemItem: .bookmarks, target: nil, action: nil)
let saveButton = UIBarButtonItem(barButtonSystemItem: .camera, target: nil, action: nil)
let spaceFlexToolbar = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceToolbar = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spaceToolbar.width = 200
self.setToolbarItems([spaceFlexToolbar, sendButton, spaceToolbar, saveButton, spaceFlexToolbar], animated: true)
self.navigationController?.setToolbarHidden(true, animated: true)
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if self.isEditing {
self.editButtonItem.title = "選択"
self.navigationController?.setToolbarHidden(false, animated: true)
} else {
self.editButtonItem.title = "完了"
self.navigationController?.setToolbarHidden(true, animated: true)
}
}
NavigationControllerのツールバーはgetしかない
var toolbar: UIToolbar! { get }
このプロパティには、ナビゲーションコントローラーによって管理される組み込みツールバーへの参照が含まれています。 このツールバーへのアクセスは、ツールバーからアクションシートを提示したいクライアントにのみ提供されます。 UIToolbarオブジェクトを直接変更しないでください。
このツールバーのコンテンツの管理は、このナビゲーションコントローラーに関連付けられたカスタムビューコントローラーを介して行われます。 ナビゲーションスタック上のビューコントローラーごとに、UIViewControllerのsetToolbarItems(_:animated :)メソッドを使用して、ツールバーアイテムのカスタムセットを割り当てることができます。
このツールバーの表示は、isToolbarHiddenプロパティによって制御されます。 ツールバーは、現在表示されているView ControllerのhidesBottomBarWhenPushedプロパティにも従い、必要に応じて自動的に非表示および表示します。
これカスタムできたら使いたいけど(viewControllerのプロパティとも連動しているし)直接変更できないらしい。
レガシーカスタマイズ
- バーのスタイルを設定する
var barStyle: UIBarStyle
外観を指定するナビゲーションバーのスタイル。
enum UIBarStyle
さまざまなタイプのビューのスタイルの外観を定義します。 - タイトルの設定
var titleTextAttributes: [NSAttributedString.Key : Any]?
バーのタイトルテキストの属性を表示します。
func titleVerticalPositionAdjustment(for: UIBarMetrics) -> CGFloat
指定されたバーメトリックのタイトルの垂直位置調整を返します。
func setTitleVerticalPositionAdjustment(CGFloat, for: UIBarMetrics)
指定されたバーメトリックのタイトルの垂直位置調整を設定します。 - バーボタンアイテムの構成
var tintColor: UIColor!
ナビゲーションアイテムとバーボタンアイテムに適用する色合いの色。 - 戻るボタンの設定
var backIndicatorImage: UIImage?
戻るボタンの横に表示されている画像。
var backIndicatorTransitionMaskImage: UIImage?
プッシュおよびポップ遷移中にコンテンツのマスクとして使用される画像。 - 背景を変える
var barTintColor: UIColor?
ナビゲーションバーの背景に適用する色合いの色。
func backgroundImage(for: UIBarMetrics) -> UIImage?
指定されたバーメトリックの背景画像を返します。
func setBackgroundImage(UIImage?, for: UIBarMetrics)
指定されたバーメトリックの背景画像を設定します。
func backgroundImage(for: UIBarPosition, barMetrics: UIBarMetrics) -> UIImage?
指定されたバーの位置と一連の指標に使用する背景画像を返します。
func setBackgroundImage(UIImage?, for: UIBarPosition, barMetrics: UIBarMetrics)
特定のバーの位置と一連の指標に使用する背景画像を設定します。 - 影を追加する
var shadowImage: UIImage?
ナビゲーションバーに使用する影の画像。
カスタマイズに高さが存在しないため、navbarではできない。toolbarを作っておくしかない
myToolbar.frame = CGRect(x: myToolbar.frame.origin.x, y: myToolbar.frame.origin.y, width: myToolbar.frame.size.width, height: 20)
ものによってはこれが効くかもしれないが、navbarはダメだった。
カスタムバーなら効きそう
toolbar.frame = CGRect(x: toolbar.frame.origin.x, y: toolbar.frame.origin.y, width: toolbar.frame.size.width, height: 300)
これは効くけど、これならinit時に指定するし、あとでframe=する必要はないかな
UIViewの.translatesAutoresizingMaskIntoConstraintsがあると表示ができない?
ビューの自動サイズ変更マスクを自動レイアウト制約に変換するかどうかを決定するブール値。
var translatesAutoresizingMaskIntoConstraints: Bool { get set }
このプロパティの値がtrueの場合、システムは、ビューの自動サイズ変更マスクで指定された動作を複製する一連の制約を作成します。 これにより、ビューのフレーム、境界、または中央のプロパティを使用してビューのサイズと場所を変更し、自動レイアウト内に静的なフレームベースのレイアウトを作成することもできます。
自動サイズ変更マスクの制約により、ビューのサイズと位置が完全に指定されることに注意してください。 したがって、競合を発生させずにこのサイズまたは位置を変更するための制約を追加することはできません。 自動レイアウトを使用してビューのサイズと位置を動的に計算する場合は、このプロパティをfalseに設定してから、ビューにあいまいで競合しない一連の制約を指定する必要があります。
デフォルトでは、プログラムで作成するすべてのビューでプロパティがtrueに設定されています。 Interface Builderでビューを追加すると、システムはこのプロパティを自動的にfalseに設定します。
上をfalseにした場合は、
```swift
NSLayoutConstraint.activate([
toolbar.bottomAnchor.constraint(equalTo:view.safeAreaLayoutGuide.bottomAnchor),
toolbar.leadingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.leadingAnchor),
toolbar.trailingAnchor.constraint(equalTo:view.safeAreaLayoutGuide.trailingAnchor),
toolbar.heightAnchor.constraint(equalToConstant: 50)
])
これを追加しないと、表示されない・・・
iphoneのsafeAreaありなしに対応するならこれが必要そう
いや、これはまずい。☝️がないとスクロールされてしますツールバーになる。。。。
わかったこと
- ボタンサイズよりもバーの高さが優先される
- frameのy=0は一番上になる
let footerBarHeight: CGFloat = 50
// ツールバーのインスタンス化
let toolbar = UIToolbar(frame: CGRect(
x: 0,
y: self.view.bounds.size.height - 120,
width: self.view.bounds.size.width,
height: footerBarHeight)
)
これでやっと上手く表示されたけど、機種によって変わるので要注意
つまり、NSLayoutConstraint.activateこれ使った方が絶対良い
この辺りはもうちょい掘り下げたい
func setBackgroundImage(UIImage?, for: UIBarMetrics)
これがなぜかきかない。。。。
navigationBarはきく。toorbarがきかない。
setShadowImageは.bottomにしたらきいた。
一旦諦め
let image = UIImage(systemName: "pencil")
self.navigationController?.toolbar.setBackgroundImage(image, forToolbarPosition: .bottom, barMetrics: .defaultPrompt)
self.navigationController?.toolbar.setShadowImage(image, forToolbarPosition: .bottom)
self.navigationController?.toolbar.backgroundImage(forToolbarPosition: .topAttached, barMetrics: .default)
self.navigationController?.navigationBar.setBackgroundImage(image, for: .default)
ここでいう、ツールバーのバックグラウンドイメージだけは一切きいてくれる様子がなかったので、これは無理っぽいので、ボタンの背景で上手くできないか
これでボタン作ると上手くいかないことがあるので要注意!!
let sendButton = UIButton(frame: CGRect(x: 0, y: 0, width: 300, height: 50))
sendButton.setTitle("送信", for: .normal)
多分サイズを指定したくてこうしたんだろうが、どっちにしろボタンのサイズはタブバーの高さで制限かかるので、無視で良さそう。それよりも
let sendButtonItem = UIBarButtonItem(title: "送信", style: .plain, target: self, action: nil)
sendButtonItem.tintColor = UIColor.black
sendButtonItem.setBackgroundImage(UIImage.colorImage(color: UIColor.blue, size: CGSize(width: 150, height: 40)), for: .normal, barMetrics: .default)
これで作れば良さそう。
ちなみに、UIImageはextensionしている
extension UIImage {
class func colorImage(color: UIColor, size: CGSize) -> UIImage {
UIGraphicsBeginImageContext(size)
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size: size)
guard let context = UIGraphicsGetCurrentContext() else { fatalError("")}
context.setFillColor(color.cgColor)
context.fill(rect)
guard let image = UIGraphicsGetImageFromCurrentImageContext() else { fatalError("")}
UIGraphicsEndImageContext()
return image
}
}
let sendButtonItem = UIBarButtonItem(title: "送信", style: .plain, target: self, action: nil)
sendButtonItem.tintColor = UIColor.white
sendButtonItem.setBackgroundImage(UIImage.colorImage(color: UIColor.green, size: CGSize(width: 180, height: 80)), for: .normal, barMetrics: .default)
しかしこれだとハジがキツくなるし、そもそもサイズをしてしてバックグラウンドイメージにする時点で無理があると理解。
var isTranslucent: Bool { get set }
ツールバーが半透明の場合は、View ControllerのedgesForExtendedLayoutプロパティとextendedLayoutIncludesOpaqueBarsプロパティを構成して、ツールバーの下にコンテンツを表示します。
ツールバーにカスタムの背景画像がない場合、または背景画像のいずれかのピクセルのアルファ値が1.0未満の場合、このプロパティのデフォルト値はtrueです。 背景画像が完全に不透明な場合、このプロパティのデフォルト値はfalseです。 このプロパティをtrueに設定し、カスタム背景画像が完全に不透明である場合、UIKitは1.0未満のシステム定義の不透明度を画像に適用します。 このプロパティをfalseに設定し、背景画像が不透明でない場合、UIKitは不透明な背景を追加します。
ツールバーむずい
toolbar.isTranslucent = false
これもきかない。色の問題かと思ったけど、全く違った。
toolbar.translatesAutoresizingMaskIntoConstraints = false
toolbar.isTranslucent = false
toolbar.barTintColor = UIColor(red: 0, green: 0.53, blue: 0.1, alpha: 1.0)
toolbar.barStyle = .default
let sendButton = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
sendButton.setImage(UIImage(systemName: "paperplane.fill"), for: .normal)
sendButton.tintColor = UIColor.white
let sendButtonItem = UIBarButtonItem(customView: sendButton)
let savebutton = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
savebutton.setImage(UIImage(systemName: "folder.fill"), for: .normal)
savebutton.tintColor = UIColor.white
let saveButtonItem = UIBarButtonItem(customView: savebutton)
let spaceFlexToolbar = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceToolbar = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spaceToolbar.width = 10
toolbar.setItems([spaceFlexToolbar, sendButtonItem, spaceToolbar, saveButtonItem, spaceFlexToolbar], animated: true)
self.view.addSubview(toolbar)
NSLayoutConstraint.activate([
toolbar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
toolbar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
toolbar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
toolbar.heightAnchor.constraint(equalToConstant: 70)
])
ひとまず、この問題はこれで進めていく。
処理も追加して、これで完成
let sendButton = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
sendButton.setImage(R.image.reload_off(), for: .normal)
sendButton.tintColor = UIColor.white
sendButton.addTarget(self, action: #selector(sendData), for: .touchUpInside)
let sendButtonItem = UIBarButtonItem(customView: sendButton)
let savebutton = UIButton(frame: CGRect(x: 0, y: 0, width: 200, height: 80))
savebutton.setImage(R.image.setting_off(), for: .normal)
savebutton.tintColor = UIColor.white
savebutton.addTarget(self, action: #selector(deleteData), for: .touchUpInside)
let saveButtonItem = UIBarButtonItem(customView: savebutton)
let spaceFlexToolbar = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let spaceToolbar = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
spaceToolbar.width = 100
toolbar.setItems([spaceFlexToolbar, sendButtonItem, spaceToolbar, saveButtonItem, spaceFlexToolbar], animated: true)
このジュウジさんの記事最高だけど、setBackgroundImageがなぜ効かないのかは分からなかった
いけた!!!!!
customToolbar.setBackgroundImage(UIImage(systemName: "person.crop.square"), forToolbarPosition: .any, barMetrics: .default)
position をanyにして、barMetrics .defaultらいけたみたい!
positionが .top / .topAttached だとダメで、.bottomはいけた。
barMetricsが.compact / .compactPrompt / .defaultPrompt だとダメだった。
ちなみに、
self.navigationController?.navigationBar.setBackgroundImage(UIImage(systemName: "person.crop.square"), for: .any, barMetrics: .default)
もいけたので、ツールバーもいけそう!
こっちも
positionが .bottom / .topAttached だとダメで、.topはいけた。
barMetricsが.compact / .compactPrompt / .defaultPrompt だとダメだった。