20210110のSwiftに関する記事は8件です。

UILabelで複数行表示させるには

iOSアプリを開発し始めた上で、知らなかったがために苦戦したので、忘れないように備忘録を残す。

TL;DR

numberOfLines0 にする。(それだけ)

やってみる

UILabelを設置

Labelを表示させる簡単なアプリを作る。
storyboardでUILabelを配置して、詳細はコードで書く。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var testLabel: UILabel!


    override func viewDidLoad() {
        super.viewDidLoad()

        setupLabel()
    }

    func setupLabel() {
        testLabel.text = "ラベルだよ"
        testLabel.backgroundColor = UIColor(red: 0, green: 0, blue: 1, alpha: 0.3)
    }


}

(UILabelそのものが見やすいように薄く背景色をつける)

こんな感じ。
ラベル置いただけ.png

長い文章にしてみる

Labelに表示させる文章を1行以上になるようにしてみる。
このLabelのままだと、明らかに高さが足りないので、十分な高さにしておく。

コードを少し手直し。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var testLabel: UILabel!
    /// 高さを調整するためにConstraintを追加
    @IBOutlet weak var testLabelHeight: NSLayoutConstraint!


    override func viewDidLoad() {
        super.viewDidLoad()

        setupLabel()
    }

    func setupLabel() {
        testLabel.text = "とっても長い文章になるよ。とっても長い文章になるよ。とっても長い文章になるよ。とっても長い文章になるよ。"
        testLabel.backgroundColor = UIColor(red: 0, green: 0, blue: 1, alpha: 0.3)

        /// 複数行表示させるため
        testLabelHeight.constant = 80
    }


}

それが、こう。
ラベル伸ばす.png

えぇ...
いい感じに省略してくれてる...

行数を設定する項目があった

高さをどんなにしても、きっちり1行に収めてくれる。
泣きながら調べてみると、 行数 を設定できることがわかった。

先ほどの setupLabel() に、これを追加する。

/// 行数調整
testLabel.numberOfLines = 0

そうすると、晴れて目的通りになる。
ラベル完成.png

まとめ

デフォルトでは行数は 1 になっているので、指定した行数にしたければ、その数値を入れ込む。
何行になってもいいから、全て表示させるには 0 を入れ込めば良い。

(てっきり全部表示してくれるもんだと思い込んでいたので、とにかく不思議でした...)


ちなみに、storyboard上でもこの項目の設定はある。
storyboard項目.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] SwiftLintの使い方 (cocoapods)

installまで

ターミナルを開きます。

ターミナルで、cdの後に赤枠をドラックアンドドロップして貼り付けます。
その後、最後の/以降を削除してEnterを押します。
スクリーンショット 2021-01-10 20.18.58.png

cd /Users/sakamototatsuya/Desktop/swift/SwiftLintTestApp                 

次に以下を入力します。

pod init

これでpodfileが作成されたので、以下で開きます。

open podfile

podfileが開けるので、赤枠のようにSwiftLintを追加します。

pod 'SwiftLint'

スクリーンショット 2021-01-10 20.25.52.png

comand + s で保存して閉じます。
ターミナルに戻り、以下を入力します。

pod install

画像のようになれば、installできています。
スクリーンショット 2021-01-10 20.30.28.png

それ以降のXcodeでの操作

先程開いていたXcodeを閉じて、workspaceで開きます。
スクリーンショット 2021-01-10 20.47.27.png

数字の順番に操作していきます。
スクリーンショット 2021-01-10 20.34.15.png

+を押したら、New Run Script Phaseを選択します。
すると、Run Scriptが下に追加されます。

赤枠に以下のコードを入れます。

"${PODS_ROOT}/SwiftLint/swiftlint"

スクリーンショット 2021-01-10 20.40.55.png

たくさん警告が出てきたら機能していると思います。
スクリーンショット 2021-01-10 20.48.28.png

参考サイト

https://github.com/realm/SwiftLint

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

NavigationBarのカスタマイズ法をサンプルアプリから学ぶ

はじめに

NavigationBarをカスタマイズする方法がAppleのDeveloperサイトに載っています。
https://developer.apple.com/documentation/uikit/uinavigationcontroller/customizing_your_app_s_navigation_bar

そこにはサンプルアプリもダウンロードできるようになっており、記事とサンプルアプリの両方を見ながらNavigationBarのカスタマイズ方法を学びます。

NavigationBarをカスタマイズする方法として以下の2種類があると記載されています。

  • ViewControllerのUINavigationItemを変更することで間接的にNavigationBarを変更
  • Appearanceプロキシを使用して直接NavigationControllerを変更

概要の意味の深掘りはここではしません。
実際にサイトの説明やサンプルアプリを順に追って見ていきましょう。

BarStyleの変更

NavigationBarの外観を変更する方法です。
サンプルコードはご覧のようになっています。

// NavigationBarのスタイルを変更するbarStyleを.blackとすることで背景を黒くする
self.navigationController!.navigationBar.barStyle = .black

// isTranslucentでNavigationBarを半透明にする
self.navigationController!.navigationBar.isTranslucent = true

// NavigationBarのタイトルの色を変更
self.navigationController!.navigationBar.titleTextAttributes = [.foregroundColor: UIColor.white]

// NavigationBarのItemの色を変更
self.navigationController!.navigationBar.tintColor = #colorLiteral(red: 1, green: 0.99997437, blue: 0.9999912977, alpha: 1)

サンプルコードにコメントを入れてみました。
NavigationBarのスタイルを変更するbarStyleには実は.blackTranslucentというstyleが存在していたのですが、iOS13.0でdeprecatedになったので、stlyeを.blackに、isTranslucentをtrueにという方法を取っています。

こちらのサンプルコードが実行されると以下のような見た目になります。
Simulator Screen Shot - iPhone 12 - 2020-12-17 at 14.30.13.png

RightViewをカスタマイズする

RightViewというのはNavigationBar右側の領域でカスタムUIViewの適用やUIBarButtonItemを使用することができます。

サンプルでは、3種類のUIBarButtonItemをNavigationBarの右側に配置しています。
サンプルコードです。

// 上下の画像を設定したUISegmentedControlを生成
let segmentedControl = UISegmentedControl(items: [
    UIImage(systemName: "arrow.up")!,
    UIImage(systemName: "arrow.down")!
])
// セグメントが選択された状態を表示しない(デフォルトはfalse)
segmentedControl.isMomentary = true

// BarButtonItemのカスタムUIViewとして、segmentedControlを使用
let segmentBarItem = UIBarButtonItem(customView: segmentedControl)
// 右側にItemを設定
navigationItem.rightBarButtonItem = segmentBarItem

サイト上だと末尾2行しか掲載されてなかったので、サンプルアプリからソースコードを一部追加しました。
こちらの例ではUISegmentedControlをNavigationBar右側のバーボタン項目として設定しています。

見た目はこうなります。
NavigationBar右側に上下の画像が設定されたUISegmentedControlが表示されていると思います。
Simulator Screen Shot - iPhone 12 - 2020-12-17 at 14.46.11.png

TitleViewをカスタマイズする

navigationItem.titleViewにUIViewを設定して、NavigationBarのTitleViewをカスタマイズすることができます。
サンプルコードではUISegmentedControlを中央のカスタムTitleViewとして設定しています。

let segmentTextContent = [
    NSLocalizedString("Image", comment: ""),
    NSLocalizedString("Text", comment: ""),
    NSLocalizedString("Video", comment: "")
]
let segmentedControl = UISegmentedControl(items: segmentTextContent)
self.navigationItem.titleView = segmentedControl

Simulator Screen Shot - iPhone 12 - 2020-12-18 at 18.46.10.png

NavigationPromptの変更

PromptとはNavigationBar上部に表示される1行のテキストのことです。
UINavigationItemのpromptプロパティを使用します。

navigationItem.prompt = NSLocalizedString("Navigation prompts appear at the top.", comment: "")

promptはきちんと1行までに限定されていて、改行コードを設定しても無効でした。
改行コード以降の文字は無視されて表示されません。
また、大量の文字を設定しましたが、端末幅に収まりきらない文字は表示できるフォントサイズまで小さくされます。
adjustsFontSizeToFitWidthをtrueにしたのと同じような動きですね。
場合によっては認識できないくらいのフォントサイズに縮小されてしまうので、文字数は意識しましょう。(あまり長い文字を設定するのはオススメしません)

Simulator Screen Shot - iPhone 12 - 2020-12-18 at 19.15.17.png

NavigationBarの外観をカスタマイズする

barTintColorや背景画像を追加してNavigationBarの背景をカスタマイズします。
サンプルコードでは画像を設定する方法を紹介しています。

guard let bounds = navigationController?.navigationBar.bounds else { return }

// 色を指定して、グラデーション画像を生成  
var backImageForDefaultBarMetrics =
    UIImage.gradientImage(bounds: bounds,
                          colors: [UIColor.systemBlue.cgColor, UIColor.systemFill.cgColor])
var backImageForLandscapePhoneBarMetrics =
    UIImage.gradientImage(bounds: bounds,
                          colors: [UIColor.systemTeal.cgColor, UIColor.systemFill.cgColor])

let navigationBarAppearance = self.navigationController!.navigationBar
// デフォルト(より適切な背景画像が見つからない時に使用される)
navigationBarAppearance.setBackgroundImage(backImageForDefaultBarMetrics, for: .default)
// iPhoneで横向きのときに使用される
navigationBarAppearance.setBackgroundImage(backImageForLandscapePhoneBarMetrics, for: .compact)

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 00.59.39.png

戻るボタンのタイトルをカスタマイズ

ユーザーは戻るボタンをタップ・ホールドすることで異なるスタックレベルを素早く切り替えることができると説明されています。
サンプルコードはありませんが、サンプルアプリではスタック内の各ViewControlerのレベルに合わせてバックボタンのタイトルをカスタマイズしています。
文章だと少し伝わりづらいかもしれないので、サンプルアプリで実装されているコードを抜粋します。

func makeViewController(_ level: Int) -> UIViewController {
    let viewController = UIViewController()
    viewController.navigationItem.backButtonTitle = "\(level)"
    return viewController
}

for level in 1..<10 {
    self.navigationController?.pushViewController(
        makeViewController(level), animated: false
    )
}

self.navigationController?.pushViewController(makeViewController(10), animated: true)

各スタックのレベルに応じて戻るボタンがカスタマイズされていることがわかると思います。
10個のViewControllerを作成し、それをPUSHすることでスタック上に戻るボタンがカスタマイズされたViewControllerが積み上がります。

戻るボタンを画像でカスタマイズ

NavigationBarの戻るボタンはデフォルトのままだと、テキストと戻る矢印がセットで表示されます。
カスタマイズすることでそれを表示せず、ユーザー側で用意した画像を表示する方法です。
UINavigationBarAppearanceを使用しています。
ここでようやくAppearanceプロキシが登場してきましたね。

let backButtonBackgroundImage = UIImage(systemName: "list.bullet")

// CustomBackButtonNavControllerにあるすべてのUINavigationBarの設定を変更するためにUINavigationBarAppearanceを生成
let barAppearance =
    UINavigationBar.appearance(whenContainedInInstancesOf: [CustomBackButtonNavController.self])

// 戻るボタンを変更する(backIndicatorTransitionMaskImageも一緒に設定する必要がある)
barAppearance.backIndicatorImage = backButtonBackgroundImage
// PushやPopのトランジション時にコンテンツのマスクとして使用される画像
barAppearance.backIndicatorTransitionMaskImage = backButtonBackgroundImage

// CustomBackButtonNavControllerにあるすべてのUIBarButtonItemの設定を変更するためにUIBarButtonAppearanceを生成
let barButtonAppearance =
    UIBarButtonItem.appearance(whenContainedInInstancesOf: [CustomBackButtonNavController.self])
// 戻るボタンのテキストの位置を調整
barButtonAppearance.setBackButtonTitlePositionAdjustment(UIOffset(horizontal: 0, vertical: -5), for: .default)

戻るボタンのタイトルを取り除くためのコードも必要です。
空文字を設定してデフォルトの設定を変更していることが分かります。

let backBarButtton = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backBarButtton

これを実装すると戻るボタンは以下のような見た目になります。

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 18.35.16.png

NavigationBarのタイトル文字を大きくする

こちらは非常にシンプルに実装することができます。
ただしLargeタイトルはScrollTopの時に限定され、スクロールすると通常の表示に自動的に切り替わります。

self.navigationController?.navigationBar.prefersLargeTitles = true

ScrollTopのとき

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 18.48.37.png

Scrollしたとき

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.23.27.png

NavigationBarの外観を変更

少し前にも利用されていましたが、
UINavigationBarAppearanceとUIBarButtonItemAppearanceを使用する方法です。

let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
// 背景色を変更
appearance.backgroundColor = UIColor.systemRed
// NavigationBarのタイトル色を変更
appearance.titleTextAttributes = [.foregroundColor: UIColor.lightText]
// 通常のNavigationBarの表示
navigationItem.standardAppearance = appearance
// LargeタイトルのScrollTopの時の表示
navigationItem.scrollEdgeAppearance = appearance
// 表示モードが横向きの時の表示
navigationItem.compactAppearance = appearance

let buttonAppearance = UIBarButtonItemAppearance()
// UIBarButtonのタイトルの色を変更
buttonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.systemGreen]
navigationItem.standardAppearance?.buttonAppearance = buttonAppearance
navigationItem.compactAppearance?.buttonAppearance = buttonAppearance

let doneButtonAppearance = UIBarButtonItemAppearance()
// Doneボタンのタイトルの色を変更
doneButtonAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.systemYellow]
navigationItem.standardAppearance?.doneButtonAppearance = doneButtonAppearance
navigationItem.compactAppearance?.doneButtonAppearance = doneButtonAppearance

ここでのポイントとしてはAppearanceがstandardAppearancescrollEdgeAppearancecompactAppearance、の3種類あることです。
大まかな意味合いはソースコードのコメントに記載しています。
NavigationBarは表示モードが若干違いますので、それぞれで設定が適用されるようにしています。

standardAppearance

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.10.56.png

scrollEdgeAppearance

サンプルアプリではNavigationBarの表示はstandardなので、
scrollEdgeAppearanceの表示をご紹介するためにソースコードを追加しています。

// 追加
appearance.largeTitleTextAttributes = [.foregroundColor: UIColor.lightText]
navigationController?.navigationBar.prefersLargeTitles = true

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.21.24.png

compactAppearance

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.22.00.png

BarButtonItemにメニューを追加

メニューを追加すると、1箇所でアプリケーションの機能に簡単にアクセスすることができます。
UIBarButtonItemの右側にUIMenuを追加します。

@IBOutlet var optionsBarItem: UIBarButtonItem!

func menuHandler(action: UIAction) {
    Swift.debugPrint("Menu handler: \(action.title)")
}

override func viewDidLoad() {
    let barButtonMenu = UIMenu(title: "", children: [
        UIAction(title: NSLocalizedString("Copy", comment: ""), image: UIImage(systemName: "doc.on.doc"), handler: menuHandler),
        UIAction(title: NSLocalizedString("Rename", comment: ""), image: UIImage(systemName: "pencil"), handler: menuHandler),
        UIAction(title: NSLocalizedString("Duplicate", comment: ""), image: UIImage(systemName: "plus.square.on.square"), handler: menuHandler),
        UIAction(title: NSLocalizedString("Move", comment: ""), image: UIImage(systemName: "folder"), handler: menuHandler)
    ])
    optionsBarItem.menu = barButtonMenu
}

UIBarButtonItemにはmenuプロパティがあるので、そこにUIMenuを設定しています。
ただし、iOS14から追加されたプロパティのようなのでOSバージョンには注意してください。
サンプルではボタンを押してもログを出力しているだけなので、アプリの要件に合わせて変更すると良いと思います。

メニュー閉

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.39.31.png

メニュー開

Simulator Screen Shot - iPhone 11 Pro - 2021-01-10 at 19.39.37.png

最後に

UINavigationBarのカスタマイズ方法をご紹介しました。
私もやったことがないものもあったり、よくわかってなかったところが整理されたので勉強になりました。
参考になれば幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】カウントダウン機能の実装方法

はじめに

個人アプリ作成時にカウントダウン機能を実装したので、
備忘録がてらコマンドの共有をさせていただきます。

GitHubにコードを載せていますのでぜひご覧ください。
-> https://github.com/onishi-app/CountDown

環境
・Apple Swift version 5.3
・XCode version 12.3

完成形

今回の完成形は次のようになります。
ボタンタップ後、1秒ずつカウントダウンしていき0秒になったら画面遷移します。

カウントダウン.gif

コード

今回は、カウントダウンを行うViewController.swiftと、
画面遷移先のNextViewController.swiftを定義したのですが、
NextViewController.swiftでの処理は特にないので省略します。

カウントダウンの実装にはTimerクラスを使用したいと思います。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var countLabel: UILabel!
    @IBOutlet weak var startButton: UIButton!

    var time = 5
    var timer = Timer()

    override func viewDidLoad() {
        super.viewDidLoad()
        countLabel.text = String(time)
        startButton.layer.cornerRadius = 10
    }

    // ボタンが押された時の処理
    @IBAction func buttonAction(_ sender: Any) {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
            self.time -= 1
            self.countLabel.text = String(self.time)

            if self.time == 0 {
                self.performSegue(withIdentifier: "next", sender: nil)
            }
        })
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        timer.invalidate()
    }
}

コード説明

viewDidLoad()内では特に特殊なことはしていません。
Labelのテキスト変数timerの値にし、ボタンの角を丸くしています。

ViewController.swift
override func viewDidLoad() {
    super.viewDidLoad()
    countLabel.text = String(time)   // text変更
    startButton.layer.cornerRadius = 10   // 丸角
}

スタートボタンが押されたタイミングでカウントダウンを開始したいので、
@IBAction func buttonAction(_ sender: Any) { }内で定義します。

TimerクラスのscheduledTimer()メソッドを使用します。
withTimeIntervalは1秒、repeats(繰り返し)はtrueにします。

メソッド内の処理ですが、timeの値を1減らしLabelの値に再代入しています。
この処理により、ボタンが押されて1秒後にLabelの値も1秒下がることになります。

0秒になったら画面遷移を行うので、
if self.time == 0 { ・・・ }の箇所で画面遷移を行っています。

ViewController.swift
// ボタンが押された時の処理
@IBAction func buttonAction(_ sender: Any) {
    timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { (timer) in
        self.time -= 1
        self.countLabel.text = String(self.time)

        if self.time == 0 {
            self.performSegue(withIdentifier: "next", sender: nil)
        }
    })
}

画面遷移を行う際にタイマーを停止したいので、下記のコマンドを記述しております。

prepare(for segue: UIStoryboardSegue, sender: Any?){ }は、
performSegue()で画面遷移する際に呼ばれるメソッドです。

メソッド内では、timer.invalidate()を実行しタイマーを停止しています。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    timer.invalidate()
}

さいごに

カウントダウン機能はかなり簡単に実装することが出来るのでぜひ使ってみてください。

Timerクラスを使用すれば、iPhoneのストップウォッチの機能も実装することができます。
(Timerクラスのみでは実装することができないと思いますが・・・)

以上、最後までご覧いただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] クロージャの基礎(自分用メモ)

クロージャについてのメモ

この記事はswift実践入門とiosAcademyを参考にして作成しています。

クロージャとは

  • 再利用可能なひとまとまりの処理
  • 関数はクロージャの一種
クロージャのフォーマット
{ (引数名1: 型, 引数名2: 型) -> 戻り値の型 in
     実行文
     戻り値の設定時はreturn必須
}

関数と比較

3より大きかったらTrueを返す関数とクロージャを用意します。

特徴

  • クロージャは外部引数の指定ができない
  • クロージャはデフォルト引数も指定不可
// 関数
func isGreaterThanThree(enter number: Int) -> Bool {
    if number > 3 {
        return true
    }
    return false
}

isGreaterThanThree(enter: 4)

// クロージャ式
var myFunction: ((Int) -> Bool) = { number in
    if number > 3 {
        return true
    }
    return false
}

// クロージャは外部引数がいらない
let result = myFunction(4)

戻り値がいらないクロージャ

  • 戻り値をVoidにするとreturnがいらない
var myFunction2: ((Int) -> (Void))? = { number in
    if number > 3 {
        print("3よりも大きいですね!")
    }
}

// アンラップする
if let myrealfunc = myFunction2 {
    myrealfunc(4)
}

引数が2つのクロージャ

  • 引数が2つになるときのクロージャは以下のようになる
// 2つの値を比較する処理
var myFunction3: ((Int, Int) -> (Void))? = { number, other in
    if number > other {
        print("\(number)のほうが大きいですね!")
    }
    else {
        print("\(other)のほうが大きいですね!")
    }
}

if let unwrappedFunc3 = myFunction3 {
    unwrappedFunc3(3, 4)
}

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

テストです

1 testです

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】フェードイン・アウト機能の実装方法

はじめに

個人アプリ作成時にフェードイン・アウト機能を実装したので、
コマンドの共有をさせていただきます。

GitHubにコードを載せていますのでぜひご覧ください。
-> https://github.com/onishi-app/FeedInOut

環境

・Apple Swift version 5.3
・XCode version 12.3

完成形

⚠︎4秒おきにフェードイン・アウトが始まります。
nC9RSKQZk5ihDQ0K6HQs1610263334-1610263350.gif

コード

コードの完成形は下記のようになります。

@IBOutlet weak var button: UIButton!で分かる通り、
StoryBoardにオブジェクトを追加しコードと連携しているので
全文コピーしてもコンパイルエラーになります。

ViewController.swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    var timer = Timer()

    override func viewDidLoad() {
        super.viewDidLoad()

        button.layer.cornerRadius = 15

        // timer実装
        timer = Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true, block: { (timer) in
            self.animateView(self.button)
        })

    }

    // フェードイン・アウトメソッド
    func animateView(_ viewAnimate: UIView) {
        UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn) {
            viewAnimate.alpha = 0
        } completion: { (_) in
            UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn) {
                viewAnimate.alpha = 1
            }
        }
    }

    // ボタンが押された時の処理
    @IBAction func buttonAction(_ sender: Any) {
        print("ボタンが押されました。")
    }
}

呼び出し方法

self.animateView(self.button)
フェードイン・アウトのメソッドを呼び出しています。

ViewController.swift
// timer実装
timer = Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true, block: { (timer) in
    self.animateView(self.button)
})

コードの説明

〜フェードイン・アウト〜

フェードイン・アウトを行うためのメソッドanimateView()を定義します。
今回は、UIKitのUIViewクラスに実装されているanimate()メソッドを使います。

ViewController.swift
// フェードイン・アウトメソッド
func animateView(_ viewAnimate: UIView) {
    UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn) {
        viewAnimate.alpha = 0
    } completion: { (_) in
        UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseIn) {
            viewAnimate.alpha = 1
        }
    }
}

UIViewクラスの中にはいくつかのanimate( )メソッドが記述されているのですが、
今回は下記のメソッドを使用していきたいと思います。

UIKit.UIView
open class func animate(withDuration duration: TimeInterval, delay: TimeInterval, options: UIView.AnimationOptions = [], animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil)

第一引数:withDuration duration: TimeInterval
withDurationの値は処理を行う時にかける時間を渡します。

今回は、withDuration: 0.5,のように、0.5秒かけて処理を行うようにしました。

第二引数:delay: TimeInterval
delayには、遅延させる時間を渡します。

delayに1が渡されていたら、メソッドが呼ばれてから1秒後に実行されます。
今回は、delay: 0のように遅延処理は実装しておりません。

第三引数:options: UIView.AnimationOptions = []
optionsには、アニメーション処理を行う際の挙動を指定しています。

optionsには多くの種類があるので一部紹介します。

挙動
repeat アニメーションを無期限に繰り返す
autoreverse 繰り返す場合は、アニメーションを前後に実行します
curveEaseInOut 始めと終わりを緩める動き(デフォルト)
curveEaseIn 始めを緩める動き
curveEaseOut 終わりを緩める動き
curveLinear 等速

この他にも色々あるので気になる方は調べてみてください!

今回は、options: .curveEaseInのように、
はじめの動きを少し緩やかにしています。

第四引数:animations: @escaping () -> Void
animationsには、実行する処理を記述します。

クロージャとして定義されているのでクロージャの形で書きましょう。

今回は、viewAnimate.alpha = 0のように、
引数で渡されてきた値のalpha(透過)を0.5秒かけて0にしています。

alpha = 0 ということは透明にするということです。

第五引数:completion: ((Bool) -> Void)? = nil
completionには、処理が終了した後の処理を記述します。

今回は、UIView.animate( ・・・ )のように、
処理後にまたアニメーション処理を実行しています。

2回目のアニメーション処理は、0.5秒かけてalpha(透過)を1にしています。
つまり、表示されている状態にしている訳です。

2回目のcompletionは、行いたい処理が無いので記述していません。

〜Timerの実装〜

次にTimerの実装についてです。

Foundationに実装されているTimerクラスを使用します。
Timerクラスでは、一定の時間で繰り返し処理を行うことができる機能などが備わっています。

ViewController.swift
var timer = Timer()

// timer実装
timer = Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true, block: { (timer) in
    self.animateView(self.button)
})

Timer.scheduledTimer( ・・・ )が繰り返しの処理になります。

今回は、viewDidLoad( )内に記述しているので、
画面が読み込まれた時点でTimerがスタートされます。

scheduledTimer( )メソッドについて

第一引数:withTimeInterval
こちらは、処理が何秒後に行われるかを記述します。

第二引数:repeats
こちらは、繰り返し処理を行うかどうかを指定します。

trueの場合は繰り返し処理を行い、falseの場合は一度だけ行います。

今回の場合はtrueなので、timerが呼び出されてから4秒後に1回目、
1回目の処理が呼び出されたてから4秒後に2回目・・・という感じで繰り返します。

フェードイン・アウトの時間が合計で1秒あるので、
何もアニメーションが行われない時間が3秒あることになります。

第三引数:block
こちらは、行いたい処理を記述します。
クロージャなので、関数の呼び出しなどにはselfキーワードをつける必要があります。

今回は、self.animateView(self.button)のように
フェードイン・アウトを4秒おきに繰り返し実行しています。

最後に

これでフェードイン・アウト機能の実装完了です。

ただ、現状一つ弱点があります。
というのも、アニメーション中はボタンが反応しないことです。

なので、アニメーション中の1秒間はボタンがタップできず、
フェードインしてから次のフェードアウトまでの3秒間しかタップできません。

もしかしたらアニメーション中に処理を行う方法もあるかもしれませんが、
ぱっと見調べた感じ分からなかったので分かり次第追記したいと思います。

とりあえずは、ボタンをビューに変えてその上に同じサイズの透明のボタンを実装し、
そちらをタップするようにしておこうと思います・・・。

ご存知の方教えて頂けますと幸いです。

楽に実装できるのでぜひ皆さん使って見てください。

以上、最後までご覧いただきありがとうございました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swift クロージャについてのアウトプット!

実行環境

Xcode 12.2
Swift 5.3.1

はじめに

初学者の人が必ずと言っていいほど疑問を抱くポイントである「クロージャ」について初学者の私がアウトプットしながら解説していきます!

わかりづらい点や間違っている点があればご指摘ください〜

クロージャとは

クロージャの機能は、ブロック{}で囲んだ処理を実行すると言ったもので関数ととてもよく似ています。
関数はfuncで宣言しますが、クロージャは定数や変数を宣言するときと同様にvarやletを使って宣言します。

早速記述の仕方を見ていきましょう!

let closure1 = { (num1:Int, num2:Int) -> Int in
    return num1 + num2
}

上記したものがクロージャの書き方になります。
num1、num2では引数を指定し-> Intの部分では戻り値の型を宣言しています。そしてinの後に処理を記述します。しかし、クロージャは簡略化して書くこともできます。
例えば、引数や戻り値がない場合は()やVoidと記述することができます。また、(引数) -> 戻り値の型 inも省略して処理だけ書くこともできます。

// 引数と戻り値がない場合
let closure2 = { () -> Void in
    print("クロージャ2")
}
closure2() // クロージャ2

// 戻り値だけがない場合
let closure3 = { (num1: Int,num2: Int) -> Void in
    print(num1 * num2)
}
closure3(8, 9) // 72

// 引数と戻り値がない場合はここまで省略することもできます!
let closure4 =  {
    print("クロージャ4")
}
 closure4() // クロージャ4

Voidではなく()と書くこともできます!

ここまででなんとなく記述の仕方と簡略ができるんだなということはわかっていただけたと思います。

func関数ではなくクロージャを使うメリットは?

クロージャを使うメリットは場合によってはfunc関数よりも見やすかったりシンプルに記述できたりする点です。とは言っても私自身ここはクロージャ使うべきだなーとかは正直まだわかってません? 
より高度な部分で必要になってくる感じなのかな?

最後に

クロージャの記述に関して良いアウトプットになりました!今後もメモ感覚でqiitaを更新していけたらなと思っていますので、よろしくお願いします。

参考URL

開発現場で役に立つSwiftのクロージャの使い方
https://arma-search.jp/article/swift-closure#i-3

【Swift入門】クロージャの使い方をわかりやすく解説!
https://www.sejuku.net/blog/34503

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む