FanpowerPackage
Swift 包以显示 Fanpower 小部件
将 Fanpower Swift 包添加到您的项目中
Swift 包管理器
Swift 包管理器 是一个用于自动分发 Swift 代码的工具,并集成到 swift
编译器中。
一旦您设置了您的 Swift 包,将 FanPower Swift 包作为依赖项添加,就像将它添加到 Package.swift
中的 dependencies
值一样简单。
dependencies: [
.package(url: "https://github.com/RocketFarm/fanpower-swift-package.git", .exact(version: "0.0.49"))
]
CocoaPods
# Podfile
source 'https://github.com/CocoaPods/Specs.git'
target 'YOUR_TARGET_NAME' do
pod 'FanpowerPackage', '0.0.49
end
替换YOUR_TARGET_NAME,然后,在Podfile目录中输入
$ pod install
示例用法
初始化小部件
import UIKit
import FanpowerPackage
class ViewController: UIViewController {
@IBOutlet weak var fanPowerView: FanPowerView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
fanPowerView.setup(
tokenForJwtRequest: "your-tokenForJwtRequest",
publisherToken: "your-publisherToken",
publisherId: "your-publisherId",
shareUrl: "your-shareUrl",
propIds: ["00001", "00002"] //Optional parameter, replace with your list of prop IDs. Can be a list of a single ID.
) {
//self.fanPowerView has completed initialization and is ready to be displayed
self.fanPowerView.isHidden = false
}
}
}
tokenForJwtRequest
、publisherToken
和 publisherId
应由 FanPower 提供。shareUrl
是当用户使用小部件的分享功能时将要分享的 URL。它也用于创建推荐 URL。如果不使用 propIds
参数,小部件将使用您账户中的所有活动属性。
清除用户会话(注销)
import FanpowerPackage
...
FanPower.logout()
大多数应用程序会将此添加到现有的注销流程中。
添加服装字体
在将FanpowerPackage添加到您的项目后,将字体文件从Sources/FanpowerPackage/Resources/Fonts/Outfit-VariableFont_wght.ttf
复制到您的项目,并按照https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app中的说明添加字体
添加不锈钢字体
如果您的应用程序使用不锈钢字体,在将FanpowerPackage添加到您的项目后,将字体文件从Sources/FanpowerPackage/Resources/Fonts/Stainless-Black.otf
、Sources/FanpowerPackage/Resources/Fonts/Stainless-Bold.otf
和Sources/FanpowerPackage/Resources/Fonts/Stainless-Regular.otf
中复制到您的项目,并按照https://developer.apple.com/documentation/uikit/text_display_and_fonts/adding_a_custom_font_to_your_app中的说明添加字体
ScrollableFanPowerView
使用先决条件
在网页视图上放置一个 ScrollableFanPowerView
。应将 ScrollableFanPowerView
限制在网页视图的边缘。 ScrollableFanPowerView
应具有清晰的颜色背景。
ScrollableFanPowerView
的示例视图控制器
import UIKit
import FanpowerPackage
import WebKit
class ViewController: UIViewController {
@IBOutlet weak var fanpowerView: ScrollableFanPowerView!
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.scrollView.delegate = self
webView.navigationDelegate = self
webView.loadHTMLString("<html><head><meta name='viewport' content='initial-scale=1, user-scalable=no, width=device-width' /></head><body style=\"-webkit-text-size-adjust:none;color:black;\"><p>This weekend, NASCAR’s premier series returns to Nashville Superspeedway for just the second time.</p><p>The Cup Series heads back to the 1.33-mile concrete oval in Lebanon, Tennessee, for the Ally 400 on Sunday (5 p.m. ET, NBC/NBC Sports App, MRN, SiriusXM NASCAR Radio) after the series’ off weekend.</p> <div style=\"height:750px;\" id=\"pu-prop-embed\" class=\\\"pu-prop-embed\\\" data-pickup-prop-id=\\\"25452\\\"><section><a href=\\\"https://playpickup.com/news/Array / surez-vs-chastain-who-wins-in-nashville - 25452\\\" rel=\\\"follow\\\" title=\\\"Suárez vs. Chastain: Who wins in Nashville? - Powered By PickUp\\\">Suárez vs. Chastain: Who wins in Nashville? - Powered By PickUp</a></section></div> <p>[Repeated content] This weekend, NASCAR’s premier series returns to Nashville Superspeedway for just the second time.</p><p>The Cup Series heads back to the 1.33-mile concrete oval in Lebanon, Tennessee, for the Ally 400 on Sunday (5 p.m. ET, NBC/NBC Sports App, MRN, SiriusXM NASCAR Radio) after the series’ off weekend.</p></body></html>", baseURL: nil)
}
func positionOfElement(withId elementID: String) {
let js = "function f(){ var r = document.getElementById('%@').getBoundingClientRect(); return r.top+''; } f();"
webView?.evaluateJavaScript(String(format: js, elementID)) { object, error in
if let object = object {
let stringY = String(describing: object)
self.fanpowerView.setup(heightConstant: 750, //This value could be calculated the same way topMarginConstant is
topMarginConstant: CGFloat(truncating: NumberFormatter().number(from: stringY)!)
* self.webView.scrollView.zoomScale,
bottomMarginConstant: 1500, //This value could be calculated the same way topMarginConstant is
tokenForJwtRequest: "your-tokenForJwtRequest",
publisherToken: "your-publisherToken",
publisherId: "your-publisherId",
shareUrl: "your-shareUrl",
referenceFrame: self.webView.frame, //Passing nil for this param will make the scrollview full-screen
propIds: ["00001", "00002"] ) { //Optional parameter, replace with your list of prop IDs. Can be a list of a single ID.
self.fanpowerView.isHidden = false
self.fanpowerView.setCollectionViewLayout() //This line allows the widget to update its UI layout after it has been moved
}
}
}
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
fanpowerView.setContentOffset(offset: webView.scrollView.contentOffset)
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
positionOfElement(withId: "pu-prop-embed")
}
}
ScrollableFanPowerView
使用嵌入推文时使用 先决条件
在网页视图上放置一个 ScrollableFanPowerView
。应将 ScrollableFanPowerView
限制在网页视图的边缘。 ScrollableFanPowerView
应具有清晰的颜色背景。网页视图的 HTML 将包括一个嵌入的推文。
ScrollableFanPowerView
的示例视图控制器
import UIKit
import FanpowerPackage
import WebKit
class ViewController: UIViewController {
@IBOutlet weak var fanpowerView: ScrollableFanPowerView!
@IBOutlet weak var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.scrollView.delegate = self
//navigation delegate is not needed for this implementation
let tweet = "<blockquote id=\"tweet\" class=\"twitter-tweet\"><p lang=\"en\" dir=\"ltr\">Sunsets don't get much better than this one over <a href=\"https://twitter.com/GrandTetonNPS?ref_src=twsrc%5Etfw\">@GrandTetonNPS</a>. <a href=\"https://twitter.com/hashtag/nature?src=hash&ref_src=twsrc%5Etfw\">#nature</a> <a href=\"https://twitter.com/hashtag/sunset?src=hash&ref_src=twsrc%5Etfw\">#sunset</a> <a href=\"https://#/YuKy2rcjyU\">pic.twitter.com/YuKy2rcjyU</a></p>— US Department of the Interior (@Interior) <a href=\"https://twitter.com/Interior/status/463440424141459456?ref_src=twsrc%5Etfw\">May 5, 2014</a></blockquote> <script async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"></script>"
webView.loadHTMLString("<html><head><meta name='viewport' content='initial-scale=1, user-scalable=no, width=device-width' /></head><body style=\"-webkit-text-size-adjust:none;color:black;\">"+tweet+"<p>This weekend, NASCAR’s premier series returns to Nashville Superspeedway for just the second time.</p><p>The Cup Series heads back to the 1.33-mile concrete oval in Lebanon, Tennessee, for the Ally 400 on Sunday (5 p.m. ET, NBC/NBC Sports App, MRN, SiriusXM NASCAR Radio) after the series’ off weekend.</p> <div style=\"height:750px;\" id=\"pu-prop-embed\" class=\\\"pu-prop-embed\\\" data-pickup-prop-id=\\\"25452\\\"><section><a href=\\\"https://playpickup.com/news/Array / surez-vs-chastain-who-wins-in-nashville - 25452\\\" rel=\\\"follow\\\" title=\\\"Suárez vs. Chastain: Who wins in Nashville? - Powered By PickUp\\\">Suárez vs. Chastain: Who wins in Nashville? - Powered By PickUp</a></section></div> <p>[Repeated content] This weekend, NASCAR’s premier series returns to Nashville Superspeedway for just the second time.</p><p>The Cup Series heads back to the 1.33-mile concrete oval in Lebanon, Tennessee, for the Ally 400 on Sunday (5 p.m. ET, NBC/NBC Sports App, MRN, SiriusXM NASCAR Radio) after the series’ off weekend.</p></body></html>", baseURL: nil)
twitterHeightTest()
}
func twitterHeightTest() {
var isTallEnough = false
let tooShortHeight = 10 //value to be determined by the developer
let heightTestInterval = 0.5 //code checks for twitter load every 0.5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + heightTestInterval) { [weak self] in
let js = "function f(){ var r = document.getElementsByClassName('%@')[0].getBoundingClientRect(); return r.height+''; } f();"
self?.webView?.evaluateJavaScript(String(format: js, "twitter-tweet")) { object, error in
if let object = object {
let stringY = String(describing: object)
print("tweet height is \(stringY)")
let intHeight = Int(stringY) ?? 0
if intHeight > tooShortHeight {
isTallEnough = true
}
}
if !isTallEnough {
self?.twitterHeightTest() //repeat the test until it succeeds or the nav controller is deallocated
} else {
self?.positionOfElement(withId: "pu-prop-embed")
}
}
}
}
func positionOfElement(withId elementID: String) {
let js = "function f(){ var r = document.getElementById('%@').getBoundingClientRect(); return r.top+''; } f();"
webView?.evaluateJavaScript(String(format: js, elementID)) { object, error in
if let object = object {
let stringY = String(describing: object)
self.fanpowerView.setup(heightConstant: 750, //This value could be calculated the same way topMarginConstant is
topMarginConstant: CGFloat(truncating: NumberFormatter().number(from: stringY)!)
* self.webView.scrollView.zoomScale,
bottomMarginConstant: 1500, //This value could be calculated the same way topMarginConstant is
tokenForJwtRequest: "your-tokenForJwtRequest",
publisherToken: "your-publisherToken",
publisherId: "your-publisherId",
shareUrl: "your-shareUrl",
referenceFrame: self.webView.frame, //Passing nil for this param will make the scrollview full-screen
propIds: ["00001", "00002"] ) { //Optional parameter, replace with your list of prop IDs. Can be a list of a single ID.
self.fanpowerView.isHidden = false
self.fanpowerView.setCollectionViewLayout() //This line allows the widget to update its UI layout after it has been moved
}
}
}
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
fanpowerView.setContentOffset(offset: webView.scrollView.contentOffset)
}
}