[Swift] StoryBoardを使わず画面を作る
StoryBoardの使い方(というか細かい設定)がよく分からず、コーディングで全部作ってやる! ってことで、画面表示まで作ってみました。(iOS用です)

自動で作成されるStoryBoardなど、不要なものは削除しますし、少ない方が良い!
ってことで。
削除したファイル
・Main.storyboard
・LaunchScreen.storyboard
そして、プロファイル定義で、StoryBoardを設定している箇所を変更

BasicSettingViewController.swift
画面の定義(オブジェクト類)は、viewDidLoad()の中に書いても良かったのだけど、 オブジェクトの数が多くなったり、複雑な画面を作ろうとした場合、外出しにした方が見やすいかな〜 と思い、BasicSettingViewを作成して組み込んでみました。
BasicSettingView.swift
Extensions.swift
セグメントコントロールのレイアウトは、centerで中心位置を渡してます。
幅は、表示セグメントの幅と数に依存するので、setWidthで各セグメントの幅を計算して設定します。
あとは、AppDelegateを修正。
これで、テスト実行すると、画面が表示されます。
まだベタ書きが多くて、美しくないソースなので、のんびりと綺麗に仕上げていきたいと思います。
このクラスにこんなメソッドがあれば便利なのに!
という要望に、比較的簡単に対応できる。
日本円の金額表示関連の処理は、拡張したら便利になりました。
ちょっとした事ですが、おぉ!! ってなりました(笑
金額をIntにしてたら、USDとか扱えないんじゃない!? とか
実はもっと良い方法があるのに・・・ とか
色々あるかもしれませんけどね。

プロジェクト作成
とりあえず、プロジェクトは「Single View App」を選択。自動で作成されるStoryBoardなど、不要なものは削除しますし、少ない方が良い!
ってことで。
削除したファイル
・Main.storyboard
・LaunchScreen.storyboard
そして、プロファイル定義で、StoryBoardを設定している箇所を変更

ファイルを追加
ViewController
自動生成されているViewControllerの名前をBasicSettingViewController変更して、コーディングを追加。BasicSettingViewController.swift
import UIKit class BasicSettingViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let basicView = BasicSettingView(frame: self.view.bounds) basicView.autoresizingMask = [.flexibleWidth, .flexibleHeight] self.view.addSubview(basicView) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() } }
画面の定義(オブジェクト類)は、viewDidLoad()の中に書いても良かったのだけど、 オブジェクトの数が多くなったり、複雑な画面を作ろうとした場合、外出しにした方が見やすいかな〜 と思い、BasicSettingViewを作成して組み込んでみました。
BasicSettingView.swift
import UIKit class BasicSettingView: UIView { // let arrayRoundUnit = ["None","10","100","1,000"] let arrayRounding = ["Over","Short"] // Screen Object let lblRoundUnit = UILabel() var sgcRoundUnit = UISegmentedControl() let lblRounding = UILabel() var sgcRounding = UISegmentedControl() // 初期化 override init(frame: CGRect) { super.init(frame: frame) buildView() } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func buildView(){ self.backgroundColor = UIColor.DefaultBGColor // ラベル lblRoundUnit.textColor = UIColor.darkText lblRoundUnit.text = "Round Unit" lblRoundUnit.textAlignment = .left self.addSubview(lblRoundUnit) // セグメントコントロール sgcRoundUnit = UISegmentedControl(items: arrayRoundUnit as [AnyObject]) self.addSubview(sgcRoundUnit) // ラベル lblRounding.textColor = UIColor.DefaultText lblRounding.text = "Rounding" lblRounding.textAlignment = .left self.addSubview(lblRounding) // セグメントコントロール sgcRounding = UISegmentedControl(items: arrayRounding as [AnyObject]) self.addSubview(sgcRounding) } override func layoutSubviews() { super.layoutSubviews() let spacing = CGFloat(8) let x = spacing var y = spacing var pos = CGPoint(x: x, y: y) // var sz = self.lblRoundUnit.sizeThatFits(self.bounds.size) sz.width = (self.bounds.width - (spacing * 2)) self.lblRoundUnit.frame = CGRect(origin: pos, size: sz) // var itemWidth = CGFloat( self.bounds.width - spacing * 2 ) / 4.0 for (i,_) in arrayRoundUnit.enumerated() { self.sgcRoundUnit.setWidth(itemWidth, forSegmentAt: i) } y = y + sz.height + spacing sz = self.sgcRoundUnit.sizeThatFits(self.bounds.size) pos = CGPoint(x: self.bounds.width / 2, y: y + sz.height / 2) self.sgcRoundUnit.center = pos // y = y + sz.height + spacing pos = CGPoint(x: x, y: y) sz = self.lblRounding.sizeThatFits(self.bounds.size) sz.width = (self.bounds.width - (spacing * 2)) self.lblRounding.frame = CGRect(origin: pos, size: sz) // itemWidth = CGFloat( self.bounds.width - spacing * 2 ) / 2.0 for (i,_) in arrayRounding.enumerated() { self.sgcRounding.setWidth(itemWidth, forSegmentAt: i) } y = y + sz.height + spacing sz = self.sgcRounding.sizeThatFits(self.bounds.size) pos = CGPoint(x: self.bounds.width / 2, y: y + sz.height / 2) self.sgcRounding.center = pos } }
init() をオーバーライドして画面オブジェクトを定義
ラベルの色は、UIColorを拡張して定義してます。 こうすると、後で一括で色を変えたい場合も一箇所修正するだけで対応できるので便利かな〜と思います。 拡張関連は1、別ファイルでまとめてます。Extensions.swift
// 色拡張 extension UIColor { static let DefaultBGColor = UIColor(red: 0.9, green: 0.9, blue: 0.9, alpha: 1) static let DefaultText = UIColor(red: 0.1, green: 0.1, blue: 0.2, alpha: 1) }
layoutSubviews()をオーバーライドして、レイアウトを調整
ラベルのレイアウトは、frameに(x,y)の位置と、(width,height)のサイズを渡して設定してます。セグメントコントロールのレイアウトは、centerで中心位置を渡してます。
幅は、表示セグメントの幅と数に依存するので、setWidthで各セグメントの幅を計算して設定します。
あとは、AppDelegateを修正。
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. window = UIWindow(frame: UIScreen.main.bounds) window?.rootViewController = BasicSettingViewController() window?.makeKeyAndVisible() return true }
これで、テスト実行すると、画面が表示されます。
まだベタ書きが多くて、美しくないソースなので、のんびりと綺麗に仕上げていきたいと思います。
おまけ
extensionってホント便利ですね。このクラスにこんなメソッドがあれば便利なのに!
という要望に、比較的簡単に対応できる。
日本円の金額表示関連の処理は、拡張したら便利になりました。
// Int型の拡張 extension Int { // Intを3桁カンマ表記の文字列に変換 var decimalStr: String { let decimalFormatter = NumberFormatter() decimalFormatter.numberStyle = NumberFormatter.Style.decimal decimalFormatter.groupingSeparator = "," decimalFormatter.groupingSize = 3 return decimalFormatter.string(from: self as NSNumber)! } } // String型の拡張 extension String { // カンマ区切りの文字列をIntに変換 // 変換できなかった場合は0を返す var decimalInt: Int { let tmp = self let temp = tmp.replacingOccurrences(of: ",", with: "") if let tmpInt = Int(temp) { return tmpInt } else { return 0 } } }これでInt型に代入した数値をdecimalStr()で3桁カンマ区切りの文字列に変換してくれるし、 String型に代入されているカンマ区切り数値をInt型に変換できる。
ちょっとした事ですが、おぉ!! ってなりました(笑
金額をIntにしてたら、USDとか扱えないんじゃない!? とか
実はもっと良い方法があるのに・・・ とか
色々あるかもしれませんけどね。
コメント
コメントを投稿