易于使用的 UI 组件,用于向用户显示简短的瞬态消息

Y - 小吃店 一个易于使用的 UI 组件,用于向用户显示简短的瞬态消息。

此框架允许您向应用程序添加瞬态应用内消息传递。多个消息将使用流体动画堆叠。消息可以完全主题化,并设置为在指定的时间间隔后过期或保留在屏幕上直到关闭。

小吃店演示动画

Licensing

Y—Snackbar is licensed under the Apache 2.0 license.

Documentation

Documentation is automatically generated from source code comments and rendered as a static website hosted via GitHub Pages at: https://yml-org.github.io/ysnackbar-ios/

Usage

Snack

A is a model that represents a floating ephemeral alert or message to be presented to the user. It consists of the following:Snack

  • alignment: Alignment for the snack view. Default is .SnackbarManager.defaultAlignment
  • title: Title for the snack view. This is an optional string and the default is nil.
  • message: Message to be displayed by . This is of type .SnackViewString
  • reuseIdentifier: A string for identifying a snack. This is of type and the default is nil.String?
  • icon: A small image to be displayed as part of the snack view. This is of type and the default is nil.UIImage?
  • duration: The total duration for which the snack will be displayed. The default is 4 seconds.
  • appearance: Sets the appearance of the . The default is SnackViewSnackView.Appearance()

Two snacks are said to be equal if either the of both snacks are equal or the and of both snacks are equal. This is made possible by the snack’s conformance to both and .reuseIdentifiertitlemessageEquatableHashable

💡 If the snack is  or  then the snack lives forever (until you swipe to dismiss it)duration.nan.zero

SnackView

A is a view that will be presented to the user through the . The content of the view is populated using a model object. It has one initializer:SnackViewSnackbarManagerSnack

  • init(snack: Snack)
    • Initializes a using the data model.SnackViewsnack

Clients can modify or set the appearance of the while creating a by setting the . This will allow the client to modify the following properties:SnackViewSnackappearance

  • title:
    • A tuple consisting of and for the title label.textColortypography
    • Default is .(.label, .systemLabel.bold)
  • message:
    • A tuple consisting of and for the message label.textColortypography
    • Default is .(.label, .systemLabel)
  • backgroundColor:
    • SnackView‘s background color. The default is .systemBackground
  • shadow:
    • SnackView‘s shadow property is of type and consists of properties such as color, opacity, etc.Shadow
    • The default is .Shadow()
  • layout:
    • SnackView‘s layout property is of type which consists of properties such as spacing between views, corner radius, etc.Layout
    • The default is .Layout()

How to get SnackView from a Snack?

func getSnackAssociatedView() -> SnackUpdatable

SnackUpdatable

  • Any object that can be updated with a new model object.Snack
  • SnackView uses this to update an existing view with new information.

SnackbarManager

All snacks are managed by the .SnackbarManager

State

  • defaultAlignment
    • It is a global mutable shared state.
    • Describes the default alignment of the snack view.
    • Default is .top

Operations

  • class func add(snack: Snack)

    • Creates a snack view using the snack passed as an argument to display a snack.

    • Depending on the alignment, duplicate snacks will be updated and pushed to the bottom or top.

  • class func remove(snack: Snack)

    • Removes a snack view using the snack passed as an argument. The will be dismissed after the last snack is removed.SnackContainerView
    • There are 3 ways by which you can remove a snack. They are as follows:
      • By calling operation.class func remove(snack: Snack)
      • When the snack has completed its duration
      • Swiping it up or down to dismiss.

Clients can control or modify the animation duration, spacing, etc of the by setting the property which is of type . This will allow the client to modify the following properties:SnackbarManagerappearanceSnackbarManager.Appearance

  • addAnimationDuration:
    • Animation duration on adding a snack.
    • Default is 0.4
  • removeAnimationDuration:
    • Animation duration on removing a snack.
    • The default is 0.4
  • snackSpacing:
    • Spacing between the snacks
    • The default is 16.0
  • contentInset:
    • The distance the content is inset from the superview.
    • The default is 16.0
  • maxSnackWidth:
    • Maximum width of a snack view.
    • Helps to keep a fixed width for a snack view on an iPad screen.
    • The default is 428.0

Default Features

Every snack added has the following default features:

  • corner radius based on appearance
  • shadow based on appearance
  • swipe enabled to dismiss snack view

Usage

  1. Importing the framework

    import YSnackbar
  2. Create a snack

    func makeSnack() -> Snack {
        Snack(
            alignment: .bottom,
            title: "Network Reachable",
            message: "You are currently online.",
            reuseIdentifier: "yml.co",
            icon: UIImage(named: "wifi"),
            duration: 8.0
          )
    }
  3. Add a snack

    // Creates a snack using `SnackbarManager.defaultAlignment = .top` 
    let snack = Snack(message: "No network")
    
    // Adds to the top of the screen
    SnackbarManager.add(snack: snack) 

    // Creates a snack with bottom alignment
    let snack = Snack(alignment: .bottom, message: "Copied to clipboard")
    
    // Adds to the bottom of the screen
    SnackbarManager.add(snack: snack) 

    // Set `SnackbarManager.defaultAlignment` to bottom
    SnackbarManager.defaultAlignment = .bottom
    
    // Creates a snack using defaultAlignment.
    let snack = Snack(message: "Copied to clipboard")
    
    // Adds to the bottom of the screen
    SnackbarManager.add(snack: snack) 
  4. Remove a snack

    let snack = Snack() 
    SnackbarManager.remove(snack)
  5. Create a custom Snack

    final class ImageSnack: Snack {
        convenience init(named: String) {
            self.init(message: named, reuseIdentifier: "co.yml.page")
        }
    
        override func getSnackAssociatedView() -> SnackUpdatable {
            SnackImageView(snack: self)
        }
    }
    
    final class SnackImageView: UIImageView {
        private(set) var snack: Snack
    
        required init(snack: Snack) {
            self.snack = snack
            super.init(image: UIImage(named: snack.message))
            setUp()
        }
    
        required init?(coder: NSCoder) { nil }
    
        private func setUp() {
            self.contentMode = .scaleAspectFit
        }
    }
    
    extension SnackImageView: SnackUpdatable {
        func update(_ snack: Snack) {
            self.image = UIImage(named: snack.message)
            self.snack = snack
        }
    }

Installation

You can add Y—Snackbar to an Xcode project by adding it as a package dependency.

  1. From the File menu, select Add Packages…
  2. Enter “https://github.com/yml-org/ysnackbar-ios” into the package repository URL text field
  3. Click Add Package

Contributing to Y—Snackbar

Requirements

SwiftLint (linter)

brew install swiftlint

Jazzy (documentation)

sudo gem install jazzy

Setup

Clone the repo and open in Xcode.Package.swift

Versioning strategy

We utilize semantic versioning.

{major}.{minor}.{patch}

e.g.

1.0.5

Branching strategy

We utilize a simplified branching strategy for our frameworks.

  • main (and development) branch is main
  • both feature (and bugfix) branches branch off of main
  • feature (and bugfix) branches are merged back into as they are completed and approved.main
  • main gets tagged with an updated version # for each release

Branch naming conventions:

feature/{ticket-number}-{short-description}
bugfix/{ticket-number}-{short-description}

e.g.

feature/CM-44-button
bugfix/CM-236-textview-color

Pull Requests

Prior to submitting a pull request you should:

  1. Compile and ensure there are no warnings and no errors.
  2. Run all unit tests and confirm that everything passes.
  3. Check unit test coverage and confirm that all new / modified code is fully covered.
  4. Run from the command line and confirm that there are no violations.swiftlint
  5. Run from the command line and confirm that you have 100% documentation coverage.jazzy
  6. Consider using to squash your last {commit-count} commits together into functional chunks.git rebase -i HEAD~{commit-count}
  7. If HEAD of the parent branch (typically ) has been updated since you created your branch, use to rebase your branch. maingit rebase main
    • Never merge the parent branch into your branch.
    • Always rebase your branch off of the parent branch.

When submitting a pull request:

  • Use the provided pull request template and populate the Introduction, Purpose, and Scope fields at a minimum.
  • If you’re submitting before and after screenshots, movies, or GIF’s, enter them in a two-column table so that they can be viewed side-by-side.

When merging a pull request:

  • Make sure the branch is rebased (not merged) off of the latest HEAD from the parent branch. This keeps our git history easy to read and understand.
  • Make sure the branch is deleted upon merge (should be automatic).

Releasing new versions

  • Tag the corresponding commit with the new version (e.g. 1.0.5)
  • Push the local tag to remote

Generating Documentation (via Jazzy)

You can generate your own local set of documentation directly from the source code using the following command from Terminal:

jazzy

This generates a set of documentation under . The default configuration is set in the default config file file./docs.jazzy.yaml

To view additional documentation options type:

jazzy --help

A GitHub Action automatically runs each time a commit is pushed to that runs Jazzy to generate the documentation for our GitHub page at: https://yml-org.github.io/ysnackbar-ios/main

GitHub

点击跳转