2017年1月28日土曜日

別のクラスのイベントの通知を受ける

iOSは内部でいろんなイベントが起こってるわけだが、別のクラスで起こったイベントの通知を受けることができる。
それがNSNotificationCenter。


  • アプリが起動したら
  • アプリがバックグラウンドからアクティブになったら
  • 別のクラスでhogeというメソッドが実行されたら

などなど。

書き方は以下のように。

NotificationCenter.default.addObserver(
     self,
   selector:#selector(textChanged),
     name: NSNotification.Name.UITextViewTextDidChange,

     object: self)

上記はUITextViewクラスのTextDidChangeメソッド(delegateメソッドだな)が発生したら、textChangeメソッドを実行しろと設定している。


NotificationCenter.default.addObserver(self,
      selector: #selector(ViewController.forActive),
      name: NSNotification.Name.UIApplicationDidBecomeActive,
      object: nil)

上記はアプリがバックグラウンドからアクティブになり、UIApplicationクラスのDidBecomeActiveが発生したらforActiveメソッドを実行しろと設定している。

object:がselfだったりnilだったりするって?
よくわかんねぇんだよ、ここw
たぶん呼ばれるメソッドや関数に渡すための引数じゃないかと思う。自分で調べてー。


なお同じNotificationでも、一定時間後とかに通知センターにiPhoneやiPadにメッセージを表示させるのはUILocalNotification

2017年1月23日月曜日

ScrollView上の部品でtouchesイベントを有効にする

ScrollView上に配置した部品はtouchesBeganとかのイベントが無効になってしまう。

やり方は意外と簡単で、以下のようにUIScrollViewを継承したクラスを作り、それを使えばいいのだ。
中にはtouchesBegan( )をoverrideし、superviewに渡すメソッドを書く。
(必要に応じてtouchesMove( )とかのメソッドも書く)

//ScrollViewtouchイベントを取得できるようにするため、overrideしたクラスを作る
class TouchableScrollView: UIScrollView
{
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        superview?.touchesBegan(touches, with: event)
    }

}

StoryboardでScrollViewを配置してるなら、そのCustomClassにこのTouchableScrollViewを指定する。
コードで配置してるならこれのインスタンスを使えばいい。

UIScrollViewはStoryboardで扱いにくい

画面の一部(または全部)をスクロールさせて大きなコンテンツを見せるためのクラスがUIScrollViewなわけだ。

画面サイズに収まるUIScrollViewの上に、画面サイズに収まらない(または拡大表示すると収まらなくなる)コンテンツを置くことで、スクロールが可能になる仕組み。
UIScrollViewは要するにでかいコンテンツを見せるための窓のようなもの。

Storyboardからも設定できるからそっちから使いたいけど、ちょっと扱いにくい。
Xcode8にもなって、いまだ完全対応してないのかよ…と愚痴ってやりたい。

具体的には、中のでかいコンテンツのサイズを設定するcontentSizeがStoryboardじゃ設定できないっぽい。
Storyboardで設定するだけじゃ以下のようなWarningが出てしまう。
コンパイル、実行はできるけど気持ち悪い。
warning: Ambiguous Layout: Scrollable content size is ambiguous for "My Scroll View".

なので通常は以下のようにコードで設定してやる必要がある。
myScrollView.contentSize = CGSize(width: 500, height: 500)

でも細かな部品を配置したいとき、コードだけでやるのは大変だよね。Constraintsの設定とかよくわかんないし。
その場合は、ダミーのUIViewをScrollViewに上下左右のマージン0、センターをScrollViewと同じにするConstraintsにして貼ってやり、さらにその上に中身のでかいコンテンツを置いてやるとWarningが消えてくれる。

UIScrollViewはまだ不慣れなので、わかんない点もあるので、いろいろ調べてみたい。

2017年1月10日火曜日

Popoverを表示

設定なんかを変更する場合に、画面全体をページ切り替えするのでなく、吹き出し型のビューを表示させるものがPopover(ポップオーバー)だ。

Pagesとかで右上のボタン押すと出るやつね。
PagesのPopover

Storyboardで簡単に作ろう

iPadだと標準だけど、iPhoneだと画面全体を覆われちゃったりするようなので、そのへんをうまいことやりながら、なおかつStoryboardで簡単に表示させようという魂胆。
だってコードで全部書くとConstraintsの設定とか大変でしょ? 中に置く部品をStoryboardで配置できるメリットは大きいよ。

メインのViewControllerの他にPopover用のViewController(仮にPopView)を作り、ViewControllerにボタンを置いて、PopViewにSegueでつないでやる。SegueのKindはPresent As Popover
このままだとデフォルトの大きさになるので、表示させる内容が少ない場合はサイズを小さくしたい。
中のViewのWidthとHeightを変えてやるとStoryboard上はサイズ変更されるけど、Runさせると変わってない。

Segueで開く際に、Segue先のViewのサイズを変えてやればいい。
そのため、prepare(for segue, sender)をoverrideする。
これから開かれるViewがdestinationプロパティで得られるので、それのpreferredContentSizeを変更すればいい。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    segue.destination.preferredContentSize = CGSize(width: 200, height: 300)
}

iPadで表示
下半分はまだ製作中ね。

iPadの場合はこれだけでいいんだけど、iPhoneは相変わらず画面全体が覆われちゃう。
そこでSegue先についてのdelegateを設定する。

当然ViewControllerの先頭にUIPopoverPresentationContollerDelegateの宣言をする。

class ViewController: UIPopoverPresentationControllerDelegate {……}


そしてSegue先のdelegate先を設定。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    segue.destination.preferredContentSize = CGSize(width: 200, height: 300)
    let popView = segue.destination.popoverPresentationController
    popView!.delegate = self
}


そして以下のdelegateメソッドを書き、UIModalPresentationStyleの値を.noneで返してやればiPhoneでも変更したサイズでPopoverが表示できるようになる。

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    return .none

}
iPhoneで表示
ちゃんと小さく表示されてる。

参考サイト

コードで書く場合とかは以下のサイトをご参考にどうぞ。

2017年1月1日日曜日

文字を修飾

LabelやTextViewなどで文字の一部の色を変えたり、フォントサイズを変えたり、影をつけたりする方法。
NSMutableAttributedStringというクラスを作り、それにattributeをaddしていくという使い方。
attributeの種類はNS○○AttributeNameというので指定する。


textViewというUITextViewがあるとして、中の文字の一部(「いうえお」の部分)を緑色で赤い影付きにする。

attributeを個別に追加

let str = NSMutableAttributedString(string: "あいうえお")

let shadow = NSShadow() //影はNSShadowというクラス
shadow.shadowColor = UIColor.red //影の色
shadow.shadowOffset = CGSize(width: 2, height: 2) //影のズレ
shadow.shadowBlurRadius = 3.0 //影の半径

//影の色
str.addAttribute(NSShadowAttributeName, value: shadow, range: NSMakeRange(1, 4))
//文字の色
str.addAttribute(NSForegroundColorAttributeName, value: UIColor.green, range: NSMakeRange(1, 4))

//textViewのattributexTextプロパティとして指定
textView.attributedText = str

attributeをまとめて追加

let str = NSMutableAttributedString(string: "あいうえお")
let shadow = NSShadow()
shadow.shadowColor = UIColor.red
shadow.shadowOffset = CGSize(width: 2, height: 2)
shadow.shadowBlurRadius = 3.0
//attributeを[]内で,区切りで複数指定
str.addAttributes([NSForegroundColorAttributeName: UIColor.green,
                   NSShadowAttributeName: shadow], range: NSMakeRange(1, 4))
textView.attributedText = str

NS○○AttributeNameのいろいろ

  • NSFontAttributeName: String // UIFont, default Helvetica(Neue) 12
    • フォント名
    • UIFontで指定
  • NSParagraphStyleAttributeName: String // NSParagraphStyle, default defaultParagraphStyle
    • 段落スタイル(文字寄せ、行末の単語をハイフンでつなぐ…など)
    • NSMutableParagraphStyleを作り、そのプロパティをいじって指定
      • .alignment = NSTextAlignmentRightなど
      • .hyphenationFactor = 0.9など 
  • NSForegroundColorAttributeName: String // UIColor, default blackColor
    • 文字色
    • UIColorで指定
  • NSBackgroundColorAttributeName: String // UIColor, default nil: no background
    • 文字背景色
    • UIColorで指定
  • NSLigatureAttributeName: String // NSNumber containing integer, default 1: default ligatures, 0: no ligatures
    • リガチャ(つなげ文字)
    • 0がなし、1があり
  • NSKernAttributeName: String // NSNumber containing floating point value, in points; amount to modify default kerning. 0 means kerning is disabled.
    • カーニング(字間)
    • 浮動小数点のNSNumberで指定
  • NSStrikethroughStyleAttributeName: String // NSNumber containing integer, default 0: no strikethrough
    • 取り消し線
    • 太さをIntで指定(フォントサイズを大きくするとそれに連れて大きくなる)
  • NSStrikethroughColorAttributeName: String // UIColor, default nil: same as foreground color
    • 取り消し線色
  • NSUnderlineStyleAttributeName: String // NSNumber containing integer, default 0: no underline
    • 下線(フォントサイズを大きくするとそれに連れて大きくなる)
    • NSUnderlineStyleSingl、NSUnderlinePatternDash(破線)などの定数も用意
  • NSUnderlineColorAttributeName: String // UIColor, default nil: same as foreground color
    • 下線の色
  • NSStrokeColorAttributeName: String // UIColor, default nil: same as foreground color
    • 中抜き文字の枠の色
  • NSStrokeWidthAttributeName: String // NSNumber containing floating point value, in percent of font point size, default 0: no stroke; positive for stroke alone, negative for stroke and fill (a typical value for outlined text would be 3.0)
    • 中抜き文字の枠の幅(フォントサイズを大きくするとそれに連れて大きくなる)
    • 負の値だと中の塗りつぶしもある
  • NSShadowAttributeName: String // NSShadow, default nil: no shadow
  • NSTextEffectAttributeName: String // NSString, default nil: no text effect
    • 文字エフェクト
    • 今のところNSTextEffectLetterpressStyleしかない。プレスしたような文字になるようだが、確認できなかった。
  • NSAttachmentAttributeName: String // NSTextAttachment, default nil
    • テキスト内に画像の埋め込み
  • NSLinkAttributeName: String // NSURL (preferred) or NSString
    • リンクの埋め込み
  • NSBaselineOffsetAttributeName: String // NSNumber containing floating point value, in points; offset from baseline, default 0
    • ベースライン・オフセットの指定
  • NSObliquenessAttributeName: String // NSNumber containing floating point value; skew to be applied to glyphs, default 0: no skew
    • 斜め文字
    • どれくらい右に傾けるかをNSNumberのfloatで。1.0で普通に傾く。負の値だと左に傾く。
  • NSExpansionAttributeName: String // NSNumber containing floating point value; log of expansion factor to be applied to glyphs, default 0: no expansion
    • 拡大(グリフの縦横比)
    • 正の値で横長、負の値で縦長
  • NSWritingDirectionAttributeName: String // NSArray of NSNumbers representing the nested levels of writing direction overrides as defined by Unicode LRE, RLE, LRO, and RLO characters.  The control characters can be obtained by masking NSWritingDirection and NSWritingDirectionFormatType values.  LRE: NSWritingDirectionLeftToRight|NSWritingDirectionEmbedding, RLE: NSWritingDirectionRightToLeft|NSWritingDirectionEmbedding, LRO: NSWritingDirectionLeftToRight|NSWritingDirectionOverride, RLO: NSWritingDirectionRightToLeft|NSWritingDirectionOverride,
    • 文字方向(アラビア語などへの対応)
  • NSVerticalGlyphFormAttributeName: String // An NSNumber containing an integer value.  0 means horizontal text.  1 indicates vertical text.  If not specified, it could follow higher-level vertical orientation settings.  Currently on iOS, it's always horizontal.  The behavior for any other value is undefined.
    • 縦書きグリフ(0が横書き、1が縦書きだが、iOSでは0しか使えない)