WhatsNewKit 1.3.7

WhatsNewKit 1.3.7

Sven Tiigi 维护。



WhatsNewKit Header Logo

Swift 5.0 CI Status Version Carthage Compatible
Platform Documentation Twitter


WhatsNewKit 使您能轻松展示您出色的全新应用程序功能。
它从头开始设计,完全可以根据您的需求进行定制。


Demo

特性

  • 根据您的需求进行定制和配置💪
  • 预定义主题和动画🎬
  • 轻松检查您的功能是否已经展示过🎁
  • 出色的 UI😍

示例

示例应用程序是查看 WhatsNewKit 在实际中如何使用的极好方式。您将简要了解可用的配置选项以及它们如何影响 WhatsNewViewController 的外观和感觉。只需打开 WhatsNewKit.xcodeproj 并运行 WhatsNewKit-Example 方案即可。

Example App

安装

CocoaPods

WhatsNewKit 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中

pod 'WhatsNewKit'

Carthage

Carthage 是一个去中心化的依赖管理工具,它构建你的依赖,并为你提供二进制框架。

要在你的 Xcode 项目中使用 Carthage 集成 WhatsNewKit,请在高 specification 文件中指定。

github "SvenTiigi/WhatsNewKit"

运行 carthage update --platform iOS 以构建框架,并将构建好的 WhatsNewKit.framework 拖入到你的 Xcode 项目中。

在你的应用程序目标“构建阶段”设置标签页上,点击“+”图标,选择“新建运行脚本阶段”,并添加框架路径,如 Carthage 入门步骤 4、5 和 6 中所述

Swift 包管理器

要使用 Apple 的 Swift 包管理器 进行集成,请将以下内容添加到你的 Package.swift

dependencies: [
    .package(url: "https://github.com/SvenTiigi/WhatsNewKit.git", from: "1.3.0")
]

手动方式

如果你不希望使用上述任何依赖管理器,你可以手动将 WhatsNewKit 集成到你的项目中。只需将 源代码 文件夹拖入到你的 Xcode 项目中即可。

使用方法

以下第一部分使用说明展示了使用 WhatsNewKit 展示你的新应用功能的简单方法。

👨‍💻请参阅 高级部分 了解更多配置选项和功能。

import WhatsNewKit

// Initialize WhatsNew
let whatsNew = WhatsNew(
    // The Title
    title: "WhatsNewKit",
    // The features you want to showcase
    items: [
        WhatsNew.Item(
            title: "Installation",
            subtitle: "You can install WhatsNewKit via CocoaPods or Carthage",
            image: UIImage(named: "installation")
        ),
        WhatsNew.Item(
            title: "Open Source",
            subtitle: "Contributions are very welcome 👨‍💻",
            image: UIImage(named: "openSource")
        )
    ]
)

// Initialize WhatsNewViewController with WhatsNew
let whatsNewViewController = WhatsNewViewController(
    whatsNew: whatsNew
)

// Present it 🤩
self.present(whatsNewViewController, animated: true)

此外,你可以使用 WhatsNewVersionStore 来确保 WhatsNewViewController 在每个版本的的应用中只显示一次。

// Initialize WhatsNewVersionStore
let versionStore: WhatsNewVersionStore = KeyValueWhatsNewVersionStore()

// Passing a WhatsNewVersionStore to the initializer
// will give you an optional WhatsNewViewController
let whatsNewViewController: WhatsNewViewController? = WhatsNewViewController(
    whatsNew: whatsNew, 
    versionStore: versionStore
)

// Verify WhatsNewViewController is available
guard let viewController = whatsNewViewController else {
    // The user has already seen the WhatsNew-Screen for the current Version of your app
    return
}

// Present WhatsNewViewController
self.present(viewController, animated: true)

👨‍💻前往 WhatsNewVersionStore 了解更多信息。

高级

如前所述,WhatsNewKit可以完全根据您的需求进行定制。本高级部分将详细介绍WhatsNewKit的所有配置可能性和特性。首先,理解WhatsNewViewController的组成部分对于定制行为和UI设计至关重要。

UILayout

WhatsNewViewController配置

WhatsNewViewController.Configuration结构体允许您根据需求定制WhatsNewViewController组件。该配置本身可以通过将要创建的初始化器传递。

// Initialize default Configuration
var configuration = WhatsNewViewController.Configuration()

// Customize Configuration to your needs
configuration.backgroundColor = .white
configuration.titleView.titleColor = .orange
configuration.itemsView.titleFont = .systemFont(ofSize: 17)
configuration.detailButton?.titleColor = .orange
configuration.completionButton.backgroundColor = .orange
// And many more configuration properties...

// Initialize WhatsNewViewController with custom configuration
let whatsNewViewController = WhatsNewViewController(
    whatsNew: whatsNew, 
    configuration: configuration
)

主题🌄

主题允许您分组自定义WhatsNewViewController.ConfigurationWhatsNewKit实现了预定义的主题,这些主题在亮色模式和深色模式中都有可用的静态属性。或者您可以创建自己的主题,以满足您的定制需求。

.darkRed .whiteRed

Theme Dark Red

Theme White Red

// Configuration with predefined Dark Red Theme
let darkRed = WhatsNewViewController.Configuration(
    theme: .darkRed
)

// Apply predefined White Red Theme to Configuration
var configuration = WhatsNewViewController.Configuration()
configuration.apply(theme: .whiteRed)

// Or create your own Theme and initialize a Configuration with your Theme
let myTheme = WhatsNewViewController.Theme { configuration in
    configuration.backgroundColor = .white
    configuration.titleView.titleColor = .orange
    configuration.itemsView.titleFont = .systemFont(ofSize: 17)
    configuration.detailButton?.titleColor = .orange
    configuration.completionButton.backgroundColor = .orange
    // ...
}

// Initialize a Configuration with your Theme
let configuration = WhatsNewViewController.Configuration(
    theme: myTheme
)

要全面了解可用的预定义主题,请查看示例应用程序

iOS 13 深色模式

如果您希望预定义的主题如.darkRed.whiteRed自动适应当前的用户界面样式,请使用.red主题。

// Configuration with predefine `red` Theme which auto adapts to the UserInterfaceStyle
// in order to support iOS 13 Dark-Mode
let configuration = WhatsNewViewController.Configuration(
    theme: .red
)

兼容深色模式的主题:.blue.lightBlue.orange.purple.red.green

布局📐

WhatsNewKit 包含三种预定义的 ItemsView.Layouts

居中
Default Layout Centered Layout Right Layout
// Left Layout
configuration.itemsView.layout = .left

// Centered Layout
configuration.itemsView.layout = .centered

// Right Layout
configuration.itemsView.layout = .right

☝️默认情况下,ItemsView 布局设置为 .left

内容模式📏

ItemsView 配置中设置 ContentMode 将调整沿轴排列您的高级功能的方式。

顶部 居中 填充
ContentMode Top ContentMode Center ContentMode Fill
// ContentMode Top
configuration.itemsView.contentMode = .top

// ContentMode Center
configuration.itemsView.contentMode = .center

// ContentMode Fill
configuration.itemsView.contentMode = .fill

☝️默认情况下,ItemsView 内容模式设置为 top

内边距

此外,如果您想修改 WhatsNewViewController 组件的布局内边距,可以这样做。

// Set TitleView Insets (Default values)
configuration.titleView.insets = UIEdgeInsets(top: 50, left: 20, bottom: 15, right: 20)

// Increase the CompletionButton Bottom Inset 
configuration.completionButton.insets.bottom += 10

图像大小

为了为您的高级功能中的每个功能定义图像大小,您可以在 ItemsView 配置中设置 ImageSize

// Use the original image size as it is
configuration.itemsView.imageSize = .original

// Use the preferred image size which fits perfectly :)
configuration.itemsView.imageSize = .preferred

// Use a custom height for each image
configuration.itemsView.imageSize = .fixed(height: 25)

☝️默认情况下,ItemsView 图像大小设置为 preferred

图像着色-颜色

默认情况下,WhatsNewKit 会自动将给定配置的颜色着色到每个 WhatsNew.Item 的图像中。如果您想禁用此功能,只需将 autoTintImage 设置为 false

// Disable auto tinting images
configuration.itemsView.autoTintImage = false

☝️默认情况下,ItemsView 自动着色图像设置为 true

动画🎬

Animations

您可以通过预定义的动画类型,将动画应用于WhatsNewViewController的 所有组件。默认情况下,所有动画属性都设置为 nil ,表示不应执行动画。

// Set SlideUp Animation to TitleView
configuration.titleView.animation = .slideUp

// Set SlideRight Animation to ItemsView
configuration.itemsView.animation = .slideRight

// Set SlideLeft Animation to DetailButton
configuration.detailButton?.animation = .slideLeft

// Set SlideDown Animation to CompletionButton
configuration.completionButton.animation = .slideDown

如果您想要将动画应用于具有相同类型的所有视图,只需将其应用于配置即可。

// Global Animation-Type for all WhatsNewViewController components
configuration.apply(animation: .fade)

如果您想自定义动画,请设置 custom 枚举并传递一个动画器闭包。

// Custom Animation for DetailButton
configuration.detailButton?.animation = .custom(animator: { (view: UIView, settings: AnimatorSettings) in
    // view: The View to perform animation on
    // settings: Preferred duration and delay
})

标题模式

默认情况下,TitleView 贴在顶部。如果希望 TitleView 和 ItemsView 一起滚动,可以在 TitleView 配置中更改 titleMode

// TitleView scrolls alongside with the ItemsView
configuration.titleView.titleMode = .scrolls

// TitleView is fixed to top
configuration.titleView.titleMode = .fixed

☝️默认情况下,titleMode 设置为 .fixed

辅助标题颜色

通过在 TitleView 上设置 SecondaryColor ,可以更改某些字符的颜色。

SecondaryColor

// Set secondary color on TitleView Configuration
configuration.titleView.secondaryColor = .init(
    // The start index
    startIndex: 0,
    // The length of characters
    length: 5,
    // The secondary color to apply 
    color: .whatsNewKitLightBlue
)

☝️默认情况下,secondaryColor 设置为 nil

详细按钮

DetailButton

通过在 WhatsNewViewController.Configuration 结构中设置 DetailButton 结构,可以自定义 WhatsNewViewController 中显示的详细按钮的 title 和对应的 action。由于 DetailButton 结构声明为可选的,只有当存在 DetailButton 配置时,WhatsNewViewController 才会显示按钮

动作 描述
网站 当用户按下详细按钮时,将显示一个带有给定 URLSFSafariViewController
自定义 用户按下详细按钮后,将调用您的自定义操作
// Initialize DetailButton with title and open website at url
let detailButton = WhatsNewViewController.DetailButton(
    title: "Read more", 
    action: .website(url: "https://github.com/SvenTiigi/WhatsNewKit")
)

// Initialize DetailButton with title and custom action
let detailButton = WhatsNewViewController.DetailButton(
    title: "Read more", 
    action: .custom(action: { [weak self] whatsNewViewController in
        // Perform custom action on detail button pressed
    })
)

完成按钮

CompletionButton

完成按钮结构体配置了显示的标题和用户在按下WhatsNewViewController上的完成按钮时的操作。

动作 描述
关闭 当用户按下完成按钮时,WhatsNewViewController将会关闭。这是默认值。
自定义 用户按下完成按钮后,将调用您的自定义操作。
// Initialize CompletionButton with title and dismiss action
let completionButton = WhatsNewViewController.CompletionButton(
    title: "Continue", 
    action: .dismiss
)

// Initialize CompletionButton with title and custom action
let completionButton = WhatsNewViewController.CompletionButton(
    title: "Continue", 
    action: .custom(action: { [weak self] whatsNewViewController in
        // Perform custom action on completion button pressed
    })
)

触觉反馈📳

您可以在用户按下DetailButtonCompletionButton时,在这两个按钮上启用触觉反馈。通过设置属性或将其传递给初始化器来实现。

// Impact Feedback
button.hapticFeedback = .impact(.medium)

// Selection Feedback
button.hapticFeedback = .selection

// Notification Feedback with type
let completionButton = WhatsNewViewController.CompletionButton(
    title: "Continue", 
    action: .dismiss,
    hapticFeedback: .notification(.success)
)

☝️默认情况下,触觉反馈nil,表示不应执行触觉反馈。

iPad Adjustments

如果您希望在iPad上呈现WhatsNewViewController.Configuration时修改它,可以设置padAdjustment闭包。

// Set PadAdjustment closure
configuration.padAdjustment = { configuration in
     // Adjust TitleView FontSize
     configuration.titleView.titleFont = .systemFont(ofSize: 45, weight: .bold)
     // Invoke default PadAdjustments (Adjusts Insets for iPad)
     WhatsNewViewController.Configuration.defaultPadAdjustment(&configuration)
}

☝️默认情况下,将调用WhatsNewViewController.Configuration.defaultPadAdjustment

WhatsNewVersionStore💾

WhatsNewVersionStore

当我们谈论展示令人惊叹的新应用程序功能时,我们必须注意,如果用户安装了应用程序或更新后打开它,此类UI操作只发生一次。《WhatNewsKit》通过WhatNewsVersionStore协议提供面向协议的解决方案。

/// WhatsNewVersionStore typealias protocol composition
public typealias WhatsNewVersionStore = WriteableWhatsNewVersionStore & ReadableWhatsNewVersionStore

/// The WriteableWhatsNewVersionStore
public protocol WriteableWhatsNewVersionStore {
    func set(version: WhatsNew.Version)
}

/// The ReadableWhatsNewVersionStore
public protocol ReadableWhatsNewVersionStore {
    func has(version: WhatsNew.Version) -> Bool
}

WhatsNewViewController将以以下方式使用WhatNewsVersionStore的API。

API 描述
has(version:) 检查WhatNews.Version是否可用,并在初始化期间返回nil
set(version:) 按下完成按钮后,将设置WhatNews.Version

WhatNewsVersionStore可以作为参数传递给初始化器。如果这样做,初始化器将变为可选的。

// Initialize WhatsNewViewController with WhatsNewVersionStore
let whatsNewViewController: WhatsNewViewController? = WhatsNewViewController(
    whatsNew: whatsNew, 
    versionStore: myVersionStore
)

// Check if WhatsNewViewController is available to present it.
if let controller = whatsNewViewController {
    // Present it as WhatsNewViewController is available 
    // after init with WhatsNewVersionStore
    self.present(controller, animated: true)
} else {
    // WhatsNewViewController is `nil` this Version has already been presented
}

// Or invoke present on the WhatsNewViewController
// to avoid the need of unwrapping the optional
whatsNewViewController?.present(on: self)

☝️请注意,当您传递一个 WhatsNewVersionStore 对象时,WhatsNewViewController 构造函数将变为可选并且会检查版本是否已经被展示。

实现

如果您已经在您的应用程序中将用户设置保存到了像 RealmCoreDataUserDefaults 这样的地方,您可以将其 conson 到 WhatsNewVersionStore

// Extend your existing App-Logic
extension MyUserSettingsDatabase: WhatsNewVersionStore {
    // Implement me 👨‍💻
}

预定义实现

WhatsNewKit 提供 WhatsNewVersionStore 的两种预定义实现。

KeyValueWhatsNewVersionStore

KeyValueWhatsNewVersionStore 通过采用符合 KeyValueable 协议的对象来保存和检索 WhatsNew.Version。已经符合该协议的例如 UserDefaultsNSUbiquitousKeyValueStore🙌

// Local KeyValueStore
let keyValueVersionStore = KeyValueWhatsNewVersionStore(
    keyValueable: UserDefaults.standard
)

// iCloud KeyValueStore
let keyValueVersionStore = KeyValueWhatsNewVersionStore(
    keyValueable: NSUbiquitousKeyValueStore.default
)

// Initialize WhatsNewViewController with KeyValueWhatsNewVersionStore
let whatsNewViewController: WhatsNewViewController? = WhatsNewViewController(
    whatsNew: whatsNew, 
    versionStore: keyValueVersionStore
)
InMemoryWhatsNewVersionStore

InMemoryWhatsNewVersionStore 在内存中保存和检索 WhatsNew.Version。非常适合开发或测试阶段。👨‍💻

// Initialize WhatsNewViewController with InMemoryWhatsNewVersionStore
let whatsNewViewController: WhatsNewViewController? = WhatsNewViewController(
    whatsNew: whatsNew, 
    versionStore: InMemoryWhatsNewVersionStore()
)

WhatsNew.Version

在初始化 WhatsNew 结构体时,WhatsNewKit 会自动通过 CFBundleShortVersionString 获取当前 App 版本,并为您构建一个 WhatsNew.Version,供 WhatsNewVersionStore 协议使用,以便持久化呈现的应用版本。如果您想手动设置版本,可以像以下示例那样操作。

// Initialize Version 1.0.0
let version = WhatsNew.Version(
    major: 1,
    minor: 0,
    patch: 0
)

// Use a String literal
let version: WhatsNew.Version = "1.0.0"

// Current Version in Bundle (Default)
let version = WhatsNew.Version.current()

初始化一个 WhatsNew.Version 后,您可以将其传递给 WhatsNew 结构体的初始化器。

// Initialize WhatsNew with Title and Items
let whatsNew = WhatsNew(
    version: version,
    title: "WhatsNewKit",
    items: []
)

如果您在一个数组中持有多个 WhatsNew 结构体,您可以利用以下两个函数根据 WhatsNewVersion 获取一个 WhatsNew 结构体。

let whatsNews: [WhatsNew] = [...]

// Retrieve WhatsNew from array based on Version 1.0.0
let whatsNewVersion1 = whatsNews.get(byVersion:
    .init(major: 1, minor: 0, patch: 0)
)

// Or retrieve it via String as WhatsNew.Version is
// conform to the ExpressibleByStringLiteral protocol
let whatsNewVersion2 = whatsNews.get(byVersion: "2.0.0")

// If you want the WhatsNew for your current App-Version
// based on the CFBundleShortVersionString from Bundle.main
let currentWhatsNew = whatsNews.get()

Codable WhatsNew

WhatsNew 结构体符合 Codable 协议,这允许您通过 JSON 初始化 WhatsNew 结构体。

{
    "version": {
        "major": 1,
        "minor": 0,
        "patch": 0
    },
    "title": "WhatsNewKit",
    "items": [
        {
            "title": "Open Source",
            "subtitle": "Contributions are very welcome 👨‍💻",
            "image": "iVBORw0KGgoA..."
        }
    ]
}

WhatsNew.Item 的可选 image 属性将以 Base64 进行解码和编码。

// Encode to JSON
let encoded = try? JSONEncoder().encode(whatsNew)

// Decode from JSON data
let decoded = try? JSONDecoder().decode(WhatsNew.self, from: data)

Featured on

Contributing

欢迎贡献力量🙌 🤓

Credits

《What's New.Item》中的图片(icons8-githubicons8-puzzleicons8-approvalicons8-picture)在截图和示例应用程序中可以看到,这些图片来自icons8.com,并受Creative Commons Attribution-NoDerivs 3.0 Unported协议许可。

授权协议

WhatsNewKit
Copyright (c) 2020 Sven Tiigi <[email protected]>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.