目录
概览
SwiftEntryKit 是一个由 Swift 编写的简单但功能丰富的内容展示器。
特性
横幅或弹出窗口称为《入口》。
- 入口将在单独的 UIWindow(类型为 EKWindow)中显示,因此用户可以在入口以非侵入的方式显示时自由导航应用程序。
- 套件提供美观的预设,可用于自定义颜色和字体。
- 自定义:入口可高度自定义
- 可被定位在屏幕的顶部、中心或底部。
- 可在屏幕安全区域内或外部显示。
- 可进行样式化:具有边框、阴影和圆角。
- 它们的内容和周围背景可以被模糊、暗淡、着色或具有渐变样式。
- 转场动画可自定义——进入、退出和弹出(通过另一个入口)。
- 可以拦截对入口或屏幕的用户交互。
- 入口可以使用优先级属性排队或覆盖之前入口。
- 每个入口都有一个显示优先级属性。这意味着它只能被具有同等或更高优先级的其他入口关闭。
- 预设支持可访问性。
- 入口在平移时有可选的“橡皮筋效应”。
- 入口可选地可以通过简单的滑动手势关闭。
- 入口可选地可以注入生命周期事件:将要出现/消失/ disappeared。
- 可以为入口的显示持续时间设置状态栏样式。
- 支持导航控制器和自定义视图!
示例项目
示例项目包含各种预设和示例,您可以像修改自己的项目一样使用和修改这些预设和示例。
示例项目安装
您可以使用终端或例如Source Tree这样的git客户端。 ZIP文件不包含必要的依赖项(QuickLayout)。
终端用户
使用 git clone
带上 --recurse-submodules
参数,包括 QuickLayout 作为子模块,依此类推
$ git clone --recurse-submodules https://github.com/huri000/SwiftEntryKit.git
Git 客户端(源树)
从 https://github.com/huri000/SwiftEntryKit.git 克隆也会设置 QuickLayout 为子模块。
预设
Toast | 备注 | 悬浮窗 | 弹出窗口 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
警告 | 表单 | 评分 | 更多... |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
游戏场
noun: a place where people can play
示例应用包含一个游戏场屏幕,一个允许您自定义首选进入界面的界面。游戏场屏幕有一些限制(只能选择常量值),但您可以轻松修改代码以满足您的需求。查看它吧!
游戏场屏幕 | 顶部Toast示例 |
---|---|
![]() |
![]() |
要求
- iOS 9 或更高版本。
- Xcode 9 或更高版本。
- Swift 4.0 或更高版本。
- 该库尚未在 iOS 8.x.y 或更低版本上进行测试。
- SwiftEntryKit 严重依赖 QuickLayout - 一个使用 Swift 编写的轻量级库,用于轻松地程序化布局视图。
安装
- SwiftEntryKit自版本1.0.0起兼容Swift 5。
- SwiftEntryKit自版本0.8.1起兼容Swift 4.2。
- 使用低于Swift版本的开发者应安装发布版0.7.2。
CocoaPods
CocoaPods是Cocoa项目的一个依赖管理器。您可以使用以下命令来安装它
$ gem install cocoapods
要使用CocoaPods将SwiftEntryKit集成到您的Xcode项目中,在您的Podfile
中指定它
source 'https://github.com/cocoapods/specs.git'
platform :ios, '9.0'
use_frameworks!
pod 'SwiftEntryKit', '1.2.7'
然后,运行以下命令
$ pod install
Carthage
Carthage是一个分发的依赖管理器,它构建您的依赖项并提供二进制框架。
您可以使用以下命令通过Homebrew安装Carthage
$ brew update
$ brew install carthage
要使用Carthage将SwiftEntryKit集成到您的Xcode项目中,在您的Cartfile
中指定以下内容
github "huri000/SwiftEntryKit" == 1.2.7
Accio
Accio是一个由SwiftPM驱动的分发的依赖管理器,适用于iOS/tvOS/watchOS/macOS项目。
您可以使用以下命令通过Homebrew安装Accio
$ brew tap JamitLabs/Accio https://github.com/JamitLabs/Accio.git
$ brew install accio
要使用Accio将SwiftEntryKit集成到您的Xcode项目中,在您的Package.swift
清单中指定以下内容
.package(url: "https://github.com/huri000/SwiftEntryKit", .exact("1.2.7"))
指定"SwiftEntryKit"
为希望在其中使用的目标的依赖后,运行accio install
。
使用
快速使用
无需设置!每次您希望在屏幕上显示一个条目时,只需创建一个视图并初始化一个EKAttributes结构体。还可以参考预置使用示例和示例项目。
// Customized view
let customView = SomeCustomView()
/*
Do some customization on customView
*/
// Attributes struct that describes the display, style, user interaction and animations of customView.
var attributes = EKAttributes()
/*
Adjust preferable attributes
*/
然后,只需调用
SwiftEntryKit.display(entry: customView, using: attributes)
该工具包将用EKWindow实例替换应用程序主窗口并显示条目。
条目属性
EkAttributes 是条目的描述符。每次显示条目时,都需要EKAttributes结构体来描述条目的展示、屏幕内位置、显示时长、框架约束(如果需要)、样式(角落、边框和阴影)、用户交互事件、动画(进入/退出)等。
像这样创建一个可变的EKAttributes结构
var attributes = EKAttributes()
以下是可以在EkAttributes中修改的属性:
条目名称
条目可以有名称。当EKAttributes结构体被实例化时,它是无名的,即name
属性值为空。建议为条目设置一个有意义的名称。
attributes.name = "Top Note"
具有名称的条目可以在以后被具体引用,例如,您可以检查当前是否显示了一个特定
条目
if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: "Top Note") {
/* Do your things */
}
窗口级别
条目可以显示在应用程序主窗口之上、状态栏之上、警告窗口之上或具有自定义级别(UIWindowLevel)。
例如,将窗口级别设置为正常,如下所示
attributes.windowLevel = .normal
这将使条目出现在应用程序键窗口之上,状态栏之下。
windowsLevel
的默认值是.statusBar
。
显示位置
条目可以显示在屏幕的 顶部、中央 或 底部。
例如,将显示位置设置为 底部 等。
attributes.position = .bottom
position
的默认值是 .top
。
优先级
条目的优先级属性描述了条目被推入的方式。它提供了两种管理多个同时条目显示优先级的方案。
覆盖
如果 显示优先级 等于或高于当前显示的条目,则覆盖它。
设置 .override
优先级并使用 .max
显示优先级的示例,同时忽略已经入队的条目(在新条目消失后显示它们)。
attributes.precedence = .override(priority: .max, dropEnqueuedEntries: false)
您可以选择清除队列中的条目。
如果 dropEnqueuedEntries
为 false
,则入队条目将保留在队列中。第一个入队条目将在新条目弹出后立即显示。如果 dropEnqueuedEntries
为 true
,则在显示新条目时会清除条目队列。
入队
如果队列为空,则立即显示条目,否则将条目插入队列,直到轮到它显示。
设置 .enqueue
优先级并使用 .normal
显示优先级的示例
attributes.precedence = .enqueue(priority: .normal)
启发式方法
队列中条目优先级排序有两种可能的启发式方法。
- 显示优先级队列:条目按其显示优先级排序,然后按时间顺序排序。
- 时间顺序队列:条目仅按其时间顺序(标准队列)排序。
在开始使用 SwiftEntryKit
显示条目前,通过以下方式选择最适合您的启发式方法,只需进行一次。
EKAttributes.Precedence.QueueingHeuristic.value = .priority
或者
EKAttributes.Precedence.QueueingHeuristic.value = .chronological
EKAttributes.Precedence.QueueingHeuristic.value
的默认值是 .priority
。
优先级的默认值是 .override(priority: .normal, dropEnqueuedEntries: false)
。
显示优先级
条目的显示优先级决定了它是否可以清除其他条目,或被其他条目清除。只有具有同等或更高显示优先级的条目才能清除它。
let highPriorityAttributes = EKAttributes()
highPriorityAttributes.precedence.priority = .high
let normalPriorityAttributes = EKAttributes()
normalPriorityAttributes.precedence.priority = .normal
// Display high priority entry
SwiftEntryKit.display(entry: view1, using: highPriorityAttributes)
// Display normal priority entry (ignored!)
SwiftEntryKit.display(entry: view2, using: normalPriorityAttributes)
view2 将不会被显示!
显示时间
条目的显示时间(从条目完成进入动画的那一刻开始计算,直到退出动画开始)。
显示时间为 4 秒
attributes.displayDuration = 4
显示无限时间
attributes.displayDuration = .infinity
displayDuration
的默认值是 2
。
位置约束
该约束将条目紧密地与屏幕上下文绑定,例如:高度、宽度、最大宽度、最大高度、额外的垂直偏移量以及与安全区域相关的内容。
- 支持自动布局的条目 - 其高度从应用到其上的约束中推断。
- 不支持自动布局的条目 - 必须显式地使用
positionConstraints
的size
属性来设置其确切大小。
例如
比率边 - 表示宽度边的比例为屏幕宽度的 0.9。
let widthConstraint = EKAttributes.PositionConstraints.Edge.ratio(value: 0.9)
内在边 - 表示所需的高度值是内容高度 - 由条目的垂直约束决定
let heightConstraint = EKAttributes.PositionConstraints.Edge.intrinsic
以类似方式创建条目大小约束
attributes.positionConstraints.size = .init(width: widthConstraint, height: heightConstraint)
您还可以设置 attributes.positionConstraints.maxSize,以确保条目不会超过预定义的限制。这在处理设备方向变化时很有用。
安全区域 - 可以用来覆盖安全区域或为其着色(更多示例在示例项目中)。此代码片段表示应保留安全区域边距,不应将其包含在条目中。
attributes.positionConstraints.safeArea = .empty(fillSafeArea: false)
垂直偏移 - 可以应用到条目上的额外偏移量(除安全区域之外)。
attributes.positionConstraints.verticalOffset = 10
自动旋转 - 是否与设备方向一起自动旋转条目。默认为 true
。
attributes.positionConstraints.rotation.isEnabled = false
键盘关联 - 用于在键盘显示后绑定条目到键盘。
let offset = EKAttributes.PositionConstraints.KeyboardRelation.Offset(bottom: 10, screenEdgeResistance: 20)
let keyboardRelation = EKAttributes.PositionConstraints.KeyboardRelation.bind(offset: offset)
attributes.positionConstraints.keyboardRelation = keyboardRelation
在上述示例中,条目的底部调整到与键盘顶部(在显示时)有 10 个点的偏移。因为条目的框架可能超出屏幕边界,所以用户可能看不到整个条目——我们不希望这样。因此,添加了一个关联的额外值——值为 20 个点的 screenEdgeResistance
。即确保条目保持在屏幕内,并且始终对用户可见。在极端情况下,当设备方向是横向且键盘显示时(请参阅示例项目预设以获取更多信息)。
用户交互
用户可以与条目和屏幕进行交互。可以以各种方式拦截用户交互
与条目的任何交互(任何触摸)都会延迟其退出 3 秒
attributes.entryInteraction = .delayExit(by: 3)
在条目/屏幕上点击会立即使其消失
attributes.entryInteraction = .dismiss
attributes.screenInteraction = .dismiss
在条目上点击会被吞噬(忽略)
attributes.entryInteraction = .absorbTouches
在屏幕上点击会将事件转发到下一级窗口,在大多数情况下接收器将是应用程序窗口。在您想要显示不干扰内容(如横幅和推送通知条目)时非常有用。
attributes.screenInteraction = .forward
传递在用户点击条目时调用的额外操作
let action = {
// Do something useful
}
attributes.entryInteraction.customTapActions.append(action)
screenInteraction
的默认值是 .forward
。
entryInteraction
的默认值是 .dismiss
。
滚动行为
描述了条目在滚动时的行为,即通过滑动手势和类似 UIScrollView 的橡皮筋效果来进行删除。
禁用条目上的拖拽和滑动手势
attributes.scroll = .disabled
启用滑动、拉伸和回弹,具有抖动效果
attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
启用滑动、拉伸和回弹,具有平滑退出效果
attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .easeOut)
启用滑动但禁用拉伸
attributes.scroll = .edgeCrossingDisabled(swipeable: true)
scroll
的默认值是 .enabled(swipeable: true, pullbackAnimation: .jolt)
。
触觉反馈
设备可以产生触觉反馈,从而为每个条目添加额外的感官深度。
hapticFeedbackType
的默认值是 .none
。
生命周期事件
可以将事件注入到入口处,以便在的生命周期期间调用它们。
attributes.lifecycleEvents.willAppear = {
// Executed before the entry animates inside
}
attributes.lifecycleEvents.didAppear = {
// Executed after the entry animates inside
}
attributes.lifecycleEvents.willDisappear = {
// Executed before the entry animates outside
}
attributes.lifecycleEvents.didDisappear = {
// Executed after the entry animates outside
}
显示模式
为了使您能够完全支持任何用户界面样式,SwiftEntryKit
引入了两种专门的类型
EKColor
在光暗模式下描述颜色。EKAttributes.BackgroundStyle.BlurStyle
在光暗模式下描述模糊效果。
以下将强制SwiftEntryKit
在暗模式下显示入口。
attributes.displayMode = .dark
可能的值是:.light
、.dark
、.inferred
。默认值是.inferred
,这意味着入口将使用当前用户界面样式显示。
背景样式
入口和屏幕可以有各种背景样式,如模糊、颜色、渐变甚至图像。
以下示例表示入口和屏幕都采用清晰的背景。
attributes.entryBackground = .clear
attributes.screenBackground = .clear
彩色入口背景和较暗的屏幕背景
attributes.entryBackground = .color(color: .standardContent)
attributes.screenBackground = .color(color: EKColor(UIColor(white: 0.5, alpha: 0.5)))
渐变入口背景(对角向量)
let colors: [EKColor] = ...
attributes.entryBackground = .gradient(gradient: .init(colors: colors, startPoint: .zero, endPoint: CGPoint(x: 1, y: 1)))
视觉效果入口背景
attributes.entryBackground = .visualEffect(style: .dark)
entryBackground
和screenBackground
的默认值是.clear
。
阴影
包裹入口的阴影。
启用入口的阴影
attributes.shadow = .active(with: .init(color: .black, opacity: 0.3, radius: 10, offset: .zero))
禁用入口的阴影
attributes.shadow = .none
shadow
的默认值是.none
。
圆角
在入口周围创建圆角。
仅左上角和右下角圆角大小为10
attributes.roundCorners = .top(radius: 10)
仅左下角和右下角圆角大小为10
attributes.roundCorners = .bottom(radius: 10)
所有角圆角大小为10
attributes.roundCorners = .all(radius: 10)
无边框圆角
attributes.roundCorners = .none
roundCorners
的默认值是.none
。
边框
条目的周围边框。
添加宽度为0.5点的黑色边框
attributes.border = .value(color: .black, width: 0.5)
无边框
attributes.border = .none
border
的默认值是.none
。
动画
描述条目如何进入和退出屏幕。
- 每个动画描述符可以同时具有最多3种类型的动画。这些可以组合成单个复杂的动画!
- 翻译动画锚点可以显式设置,但其默认值根据条目的位置提供。
例如,从顶部以弹簧翻译,并缩放进入,甚至作为单个进入动画.fade in
attributes.entranceAnimation = .init(
translate: .init(duration: 0.7, anchorPosition: .top, spring: .init(damping: 1, initialVelocity: 0)),
scale: .init(from: 0.6, to: 1, duration: 0.7),
fade: .init(from: 0.8, to: 1, duration: 0.3))
entranceAnimation
和exitAnimation
的默认值是.translation
- 条目以持续0.3秒的方式进入或退出。
弹出发行行为
描述条目在弹发(由具有相等的/更高的显示优先级的条目脱落)时的行为。
条目正在以动画形式弹出
attributes.popBehavior = .animated(animation: .init(translate: .init(duration: 0.2)))
条目被覆盖(立即消失)
attributes.popBehavior = .overridden
popBehavior
的默认值是.animated(animation: .translation)
- 它以持续0.3秒的方式淡出。
状态栏
可以在显示条目的同时修改状态栏的外观。SwiftEntryKit支持基于视图控制器状态栏外观和手动设置。
设置状态栏样式相对简单
状态栏可见并具有浅色风格
attributes.statusBar = .light
状态栏不可见
attributes.statusBar = .hidden
状态栏外观将从先前上下文中推断(不会更改)
attributes.statusBar = .inferred
如果有一个已经显示的较低/相等的显示优先级的条目,状态栏将更改其样式。当条目被移除时,状态栏将恢复其初始样式。
statusBar
的默认值是.inferred
。
SwiftEntryKit的界面如下
public struct EKAttributes
// Identification
public var name: String?
// Display
public var windowLevel: WindowLevel
public var position: Position
public var precedence: Precedence
public var displayDuration: DisplayDuration
public var positionConstraints: PositionConstraints
// User Interaction
public var screenInteraction: UserInteraction
public var entryInteraction: UserInteraction
public var scroll: Scroll
public var hapticFeedbackType: NotificationHapticFeedback
public var lifecycleEvents: LifecycleEvents
// Theme & Style
public var displayMode = DisplayMode.inferred
public var entryBackground: BackgroundStyle
public var screenBackground: BackgroundStyle
public var shadow: Shadow
public var roundCorners: RoundCorners
public var border: Border
public var statusBar: StatusBar
// Animations
public var entranceAnimation: Animation
public var exitAnimation: Animation
public var popBehavior: PopBehavior
}
预定义使用示例
您可以使用SwiftEntryKit附带的一个预定义设置,遵循以下4个简单步骤
- 创建您的EKAttributes结构并设置您喜欢的属性。
- 创建EKNotificationMessage结构(内容)并设置内容。
- 创建EKNotificationMessageView(视图)并将EKNotificationMessage结构注入其中。
- 使用SwiftEntryKit类方法显示条目。
EKNotificationMessageView 预定义示例
// Generate top floating entry and set some properties
var attributes = EKAttributes.topFloat
attributes.entryBackground = .gradient(gradient: .init(colors: [EKColor(.red), EKColor(.green)], 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 = .dark
attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
attributes.positionConstraints.maxSize = .init(width: .constant(value: UIScreen.main.minEdge), height: .intrinsic)
let title = EKProperty.LabelContent(text: titleText, style: .init(font: titleFont, color: textColor))
let description = EKProperty.LabelContent(text: descText, style: .init(font: descFont, color: textColor))
let image = EKProperty.ImageContent(image: UIImage(named: imageName)!, 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)
自定义视图使用示例
// Create a basic toast that appears at the top
var attributes = EKAttributes.topToast
// Set its background to white
attributes.entryBackground = .color(color: .white)
// Animate in and out using default translation
attributes.entranceAnimation = .translation
attributes.exitAnimation = .translation
let customView = UIView()
/*
... Customize the view as you like ...
*/
// Display the view with the configuration
SwiftEntryKit.display(entry: customView, using: attributes)
显示视图控制器
从版本0.4.0开始,也支持视图控制器。
SwiftEntryKit.display(entry: customViewController, using: attributes)
备选回滚窗口
默认情况下,SwiftEntryKit完成条目展示后,应用程序代理持有的窗口再次成为键。此行为可以通过使用rollbackWindow
参数进行更改。
SwiftEntryKit.display(entry: view, using: attributes, rollbackWindow: .custom(window: alternativeWindow))
条目已消失后,提供的窗口alternativeWindow
将取代应用程序代理持有的窗口成为键。
删除条目
您可以通过在SwiftEntryKit类中简单地调用dismiss来删除当前显示的条目,同样可以
SwiftEntryKit.dismiss()
或者
SwiftEntryKit.dismiss(.displayed)
这将通过其exitAnimation属性弹动画删除条目,完成后,窗口也将被移除。
可以删除当前显示的条目并刷新队列,同样可以
SwiftEntryKit.dismiss(.all)
仅刷新队列,使任何当前显示的条目进入其自然生命周期
SwiftEntryKit.dismiss(.queue)
按名称删除特定的条目 - 无论是当前显示的还是排队的。具有指定名称的所有条目都将被删除。
SwiftEntryKit.dismiss(.specific(entryName: "Entry Name"))
删除任何显示优先级低于或等于.normal
的条目。
SwiftEntryKit.dismiss(.prioritizedLowerOrEqualTo(priority: .normal))
使用完成处理程序
注入一个将在条目删除后执行的尾部闭包。
SwiftEntryKit.dismiss {
// Executed right after the entry has been dismissed
}
当前是否显示
询问条目是否当前正在显示
if SwiftEntryKit.isCurrentlyDisplaying {
/* Do your things */
}
使用EKAttributes
中的name
属性内部,询问是否当前显示特定的条目。
if SwiftEntryKit.isCurrentlyDisplaying(entryNamed: "Top Note") {
/* Do your things */
}
队列是否包含
询问条目队列是否为空
if SwiftEntryKit.isQueueEmpty {
/* Do your things */
}
询问条目队列是否包含具有特定名称的条目
if SwiftEntryKit.queueContains(entryNamed: "Custom-Name") {
/* Do your things */
}
滑动和橡皮筋效应
条目可以垂直拖动(此功能可以使用scroll属性启用)。因此,用类似于滑动的手势删除条目是很自然的。
启用滑动手势。当滑动手势失败(没有超过速度阈值)时,平滑地将其放回。
attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .easeOut)
启用滑动手势。当滑动手势失败时,将其猛力弹回。
attributes.scroll = .enabled(swipeable: true, pullbackAnimation: .jolt)
拉回动画 的值(持续时间、阻尼和初始弹簧速度)也可以进行自定义。
滑动 | 冲击 |
---|---|
![]() |
![]() |
处理安全区域
可以使用 EEKAttributes.PositionConstraints.SafeArea 覆盖安全区域,以使用条目的内容,或者用背景颜色(例如:Toast 所做的那样)填充安全区域,或者甚至使安全区域为空(例如:浮动 所做的那样)。
SwiftEntryKit 支持 iOS 11.x.y,并且向下兼容 iOS 9.x.y,因此状态栏区域在旧版 iOS 版本中与安全区相同。
处理方向变化
SwiftEntryKit 会识别方向变化,并相应地调整条目布局。因此,如果要限制条目的宽度,可以通过设置最大值来实现,同样
var attributes = EKAttributes.topFloat
// Give the entry the width of the screen minus 20pts from each side, the height is decided by the content's contraint's
attributes.positionConstraints.size = .init(width: .offset(value: 20), height: .intrinsic)
// Give the entry maximum width of the screen minimum edge - thus the entry won't grow much when the device orientation changes from portrait to landscape mode.
let edgeWidth = min(UIScreen.main.bounds.width, UIScreen.main.bounds.height)
attributes.positionConstraints.maxSize = .init(width: .constant(value: edgeWidth), height: .intrinsic)
let customView = UIView()
/*
... Customize the view as you like ...
*/
// Use class method of SwiftEntryKit to display the view using the desired attributes
SwiftEntryKit.display(entry: customView, using: attributes)
方向变化演示 |
---|
![]() |
示例项目中的深色模式
您可以使用预设屏幕上的分段控件来调整显示模式,强制设置亮模式和暗模式。所有预设都已准备好使用深色模式,但在示例项目中只有一些演示了深色模式的功能。
Swift 和 Objective-C 互操作性
SwiftEntryKit 的 API 使用 Swift 语言专用的语法(枚举、关联值等)。因此,无法直接从 Objective-C 文件(.m、.h 或 .mm)引用 SwiftEntryKit
。
但是,通过一个简单的 .swift 类来集成 SwiftEntryKit,该类可以被视为 SwiftEntryKit
和您的 Objective-C 代码之间的适配器,相对容易地将其集成到 Objective-C 项目中。
这个项目 使用 Carthage 和 CocoaPods 进行了演示。
作者
丹尼尔·赫里,[email protected]
捐款
可以通过将比特币或以太币发送到以下地址进行捐款。
BTC | ETH |
---|---|
134TiBiUvVNt7Na5KXEFBSChLdgVDw1Hnr | 0xAe6616181FCdde4793AE749Ce21Cd5Af9333A3E2 |
![]() |
![]() |
感谢
感谢莉莉·阿扎尔,[email protected],为你那些出色的预设图标。
署名
许可
SwiftEntryKit 在MIT许可下可用。有关更多信息,请参阅LICENSE文件。
例外
请注意,在项目中使用图标需要为创作者署名。参见署名以获取创作者列表。