Help us understand the problem. What is going on with this article?

Swift(iOS)でイケてるトースト・バナー・ポップアップを導入する (SwiftEntryKit)

SwiftEntryKit

トーストやポップアップ、プッシュ通知のようなビューを簡単に導入できるすごいライブラリ SwiftEntryKit をこの記事で紹介する。いくつか同様のライブラリ(Toast-Swiftなど)を試したが、SwiftEntryKitが圧倒的にイケてるUIUXを作れると感じた。イメージは以下の通り。

Toasts Notes Floats Popups
toasts_example notes_example floats_example popups_example
Alerts Forms Rating More...
alerts_example forms_example rating_example custom_example

インストール

https://github.com/huri000/SwiftEntryKit#installation

ここに丁寧に書いてあるのでここでは言及しない。CocoaPodsやCarthageで入れるだけ。

使い方のイメージ

import SwiftEntryKit

///

func test() {
    var attributes = EKAttributes.bottomFloat // bottomFloat以外に様々なタイプがある
    // プロパティを設定していく
    // attributes.xxx = xxx
    // たとえば以下の通り
    attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.red), EKColor(UIColor.orange)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
    attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
    attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
    attributes.statusBar = .light
    attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
    attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)

    // EKNotificationMessageViewなど、EKxxxViewを作ってattributesとともにSwiftEntryKitに渡す
    // UIFont() は任意の形に変更する必要がある
    let title = EKProperty.LabelContent(text: "Sample Notification", style: .init(font: UIFont(), color: .standardContent))
    let description = EKProperty.LabelContent(text: "Body message", style: .init(font: UIFont(), color: .standardContent))
    let image = EKProperty.ImageContent(image: UIImage(named: "some image"), size: CGSize(width: 35, height: 35))
    let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)
    let notificationMessage = EKNotificationMessage(simpleMessage: simpleMessage)
    let contentView = EKNotificationMessageView(with: notificationMessage)

    // あとはSwiftEntryKit.displayを呼ぶだけ
    SwiftEntryKit.display(entry: contentView, using: attributes)
}

このライブラリでは、ビューのトップ、中央、ボトムの3つの位置(top / center / bottom)を選択でき、ビューのタイプは以下のような感じで10個以上定義されている。位置とビューのタイプを組み合わせて使うことになる。

  • EKAlertMessageView
  • EKFormMessageView
  • EKNotificationMessageView
  • EKNoteMessageView
  • EKPopUpMessageView
  • EKRatingMessageView

iOSのプッシュ通知のようなバナーを表示する

struct NotificationBanner {
    static func show(title: String, body: String, image: UIImage) {
        var attributes = EKAttributes.topFloat
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.red), EKColor(UIColor.orange)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.statusBar = .light
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)

        // UIFont() は任意の形に変更する必要がある        
        let title = EKProperty.LabelContent(text: title, style: .init(font: UIFont(), color: .white))
        let description = EKProperty.LabelContent(text: body, style: .init(font: UIFont(), color: .white))
        let image = EKProperty.ImageContent(image: image, size: CGSize(width: 35, height: 35))
        let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)
        let notificationMessage = EKNotificationMessage(simpleMessage: simpleMessage)

        let contentView = EKNotificationMessageView(with: notificationMessage)
        SwiftEntryKit.display(entry: contentView, using: attributes)
    }
}

利用するのはこんな感じ。

NotificationBanner.show(title: "Notification title", body: "Notification body", image: UIImage(named: "xxx"))

お洒落なアラートを表示する

struct Alert {
    // ここではアクションが一つの場合
    static func show(title: String, body: String, image: UIImage, action: @escaping () -> Void) {
        var attributes = EKAttributes.topFloat
        attributes.displayDuration = .infinity
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.purple), EKColor(UIColor.blue)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.screenBackground = .visualEffect(style: .prominent)
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)
        // これがないとアクションが実行されない
        attributes.entryInteraction = .absorbTouches

        // UIFont() は任意の形に変更する必要がある
        let title = EKProperty.LabelContent(text: title, style: .init(font: UIFont(), color: .white))
        let description = EKProperty.LabelContent(text: body, style: .init(font: UIFont(), color: .white))
        let image = EKProperty.ImageContent(image: image, size: CGSize(width: 35, height: 35))
        let simpleMessage = EKSimpleMessage(image: image, title: title, description: description)        

        let label = EKProperty.LabelContent(text: "OK", style: .init(font: UIFont(), color: .black))
        let button = EKProperty.ButtonContent(label: label, backgroundColor: .white, highlightedBackgroundColor: .standardBackground) {
            // dismissを自分で呼ばないとビューが消えない
            SwiftEntryKit.dismiss()
            action()
        }        
        let content = EKProperty.ButtonBarContent(with: [button], separatorColor: EKColor(UIColor.black), expandAnimatedly: true)

        let alertMessage = EKAlertMessage(simpleMessage: simpleMessage, buttonBarContent: content)
        let view = EKAlertMessageView(with: alertMessage)

        SwiftEntryKit.display(entry: view, using: attributes)
    }
}

利用するのはこんな感じ。

Alert.show(title: "Alert title", body: "Alert body") {
    print("tapped!!")
}

ポップアップを表示する

struct Popup {
    static func show(title: String, body: String, action: @escaping () -> Void) {
        var attributes = EKAttributes.centerFloat
        attributes.displayDuration = .infinity
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.purple), EKColor(UIColor.blue)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.screenBackground = .visualEffect(style: .prominent)
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)
        // これがないとアクションが実行されない
        attributes.entryInteraction = .absorbTouches
        // UIFont() は任意の形に変更する必要がある
        let title = EKProperty.LabelContent(text: title, style: .init(font: UIFont(), color: .white))
        let description = EKProperty.LabelContent(text: body, style: .init(font: UIFont(), color: .white))

        let label = EKProperty.LabelContent(text: "OK", style: .init(font: UIFont(), color: .black))
        let button = EKProperty.ButtonContent(label: label, backgroundColor: .white, highlightedBackgroundColor: .standardBackground)
        let action: EKPopUpMessage.EKPopUpMessageAction = {
            SwiftEntryKit.dismiss()
            // ここにボタン押下時のアクションを入れることができる
            action()
        }
        let popupMessage = EKPopUpMessage(title: title, description: description, button: button, action: action)
        let view = EKPopUpMessageView(with: popupMessage)

        SwiftEntryKit.display(entry: view, using: attributes)
    }
}

利用するのはこんな感じ。

Popup.show(title: "Popup title", body: "Popup body") {
    print("tapped!!")
}

フォーム付きのポップアップを表示する

struct Form {
    // フォームが1つの場合
    static func show(title: String, placeholder: String = "", image: UIImage, action: @escaping (String) -> Void) {
        var attributes = EKAttributes.centerFloat
        attributes.displayDuration = .infinity
        attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(UIColor.purple), EKColor(UIColor.blue)], startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
        attributes.screenBackground = .visualEffect(style: .prominent)
        attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.3), scale: .init(from: 1, to: 0.7, duration: 0.7)))
        attributes.shadow = .active(with: .init(color: .black, opacity: 0.5, radius: 10, offset: .zero))
        attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
        attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.bounds.width), height: .intrinsic)
        // これがないとアクションが実行されない
        attributes.entryInteraction = .absorbTouches

        let white = EKColor(UIColor.white)
        let black = EKColor(UIColor.black)
        let gray = EKColor(UIColor.gray)

        let whiteStyle = EKProperty.LabelStyle(font: UIFont(), color: white)
        let blackStyle = EKProperty.LabelStyle(font: UIFont(), color: black)

        let title = EKProperty.LabelContent(text: title, style: whiteStyle)
        let ok = EKProperty.LabelContent(text: "OK", style: blackStyle)
        let placeholder = EKProperty.LabelContent(text: placeholder, style: whiteStyle)

        let content = EKProperty.TextFieldContent(keyboardType: .asciiCapable, placeholder: placeholder, tintColor: white, displayMode: .inferred, textStyle: whiteStyle, leadingImage: image, bottomBorderColor: white)

        let button = EKProperty.ButtonContent(label: ok, backgroundColor: .white, highlightedBackgroundColor: gtray) {
            SwiftEntryKit.dismiss()
            action(content.textContent)
        }

        let view = EKFormMessageView(with: title, textFieldsContent: [content], buttonContent: button)

        SwiftEntryKit.display(entry: view, using: attributes)
    }
}

利用するのはこんな感じ。

Form.show(title: "Form title", body: "Form body") { value in
    print("input value: \(value)")
}

まとめ

他にもToast、Note、Rating等のビューが用意されているが、同様の要領で利用できる。繰り返しになるが、EKNotificationMessageViewなど、EKxxxViewを作ってattributesとともにSwiftEntryKitに渡せば良い。

ngo275
フルスタックめなエンジニアやっています
https://shuichi.tech
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした