Skip to content

Instantly share code, notes, and snippets.

@macneko-ayu
Last active April 25, 2020 13:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save macneko-ayu/c4ba1df605cc7da1e9cdafeaca86c48f to your computer and use it in GitHub Desktop.
Save macneko-ayu/c4ba1df605cc7da1e9cdafeaca86c48f to your computer and use it in GitHub Desktop.
WKInterfaceLabel to automatically scroll horizontally
import WatchKit
import Foundation
class InterfaceController: WKInterfaceController {
@IBOutlet var notEndlessLabel: WKInterfaceLabel!
@IBOutlet var endlessLabel: WKInterfaceLabel!
override func awake(withContext context: Any?) {
super.awake(withContext: context)
notEndlessLabel.setAutoHorizontalScrollText("レノくんかわいい。ごんたかわいい。あゆさんかわいい")
endlessLabel.setAutoHorizontalScrollText("レノくんかわいい。ごんたかわいい。あゆさんかわいい", isEndless: true)
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
}
override func didAppear() {
super.didAppear()
notEndlessLabel.startTimer()
endlessLabel.startTimer()
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
notEndlessLabel.stopTimer()
endlessLabel.stopTimer()
}
}
import WatchKit
private var ScrolledTextKey: UInt8 = 0
private var OriginTextKey: UInt8 = 0
private var TimerKey: UInt8 = 0
private var EndlessKey: UInt8 = 0
private var TimerStartedKey: UInt8 = 0
extension WKInterfaceLabel {
// MARK: - Public method
/// テキストを横方向に自動でスクロールする
///
/// - Parameter text: text
func setAutoHorizontalScrollText(_ text: String?, isEndless endless: Bool = false) {
guard let text = text else {
return
}
setEndless(endless)
setOriginText(NSAttributedString(string: text + "          "))
initializeText()
self.startTimer()
}
/// 自動スクロール開始
@objc func startTimer() {
// タイマーの多重起動を防ぐため、スクロール開始済の場合はreturn
if getTimerStarted() {
return
}
setTimerStarted(true)
DispatchQueue.main.async {
let timer = Timer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(self.timerUpdate), userInfo: nil, repeats: true)
self.setTimer(timer)
}
}
/// 自動スクロール停止
func stopTimer() {
getTimer().invalidate()
setTimerStarted(false)
// テキストを初期化
initializeText()
}
// MARK: - Private method
/// ラベルのテキストを更新
@objc private func timerUpdate() {
if getScrolledText().length > 1 {
let scrolledText = NSMutableAttributedString(attributedString: getScrolledText())
guard let firstCharacter = scrolledText.string.first else {
return
}
// テキストの先頭の文字を削除
scrolledText.deleteCharacters(in: NSRange(location: 0, length: 1))
// エンドレスの場合はテキストの末尾に削除した文字を追加する
if getEndless() {
scrolledText.append(addAttribute(String(firstCharacter)))
}
setScrolledText(scrolledText)
setAttributedText(getScrolledText())
} else {
// タイマーを停止
stopTimer()
if !getEndless() {
// 少し間をおき、スクロール開始
let timer = Timer(timeInterval: 2, target: self, selector: #selector(startTimer), userInfo: nil, repeats: false)
RunLoop.main.add(timer, forMode: .commonModes)
}
}
}
/// ラベルのテキストを初期化
private func initializeText() {
let attributeText = addAttribute(getOriginText().string)
setOriginText(attributeText)
setScrolledText(getOriginText())
setAttributedText(getScrolledText())
}
private func addAttribute(_ text: String) -> NSAttributedString {
// ラベルにLineBreakModeのプロパティが存在しないので、NSAttributedStringで設定する
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineBreakMode = .byClipping
let attributes: [NSAttributedStringKey: Any] = [.paragraphStyle: paragraphStyle]
return NSAttributedString(string: text, attributes: attributes)
}
// MARK: - getter/setter
private func setScrolledText(_ text: NSAttributedString) {
objc_setAssociatedObject(self, &ScrolledTextKey, text, .OBJC_ASSOCIATION_RETAIN)
}
private func getScrolledText() -> NSAttributedString {
guard let object = objc_getAssociatedObject(self, &ScrolledTextKey) as? NSAttributedString else {
return NSAttributedString(string: "")
}
return object
}
private func setOriginText(_ text: NSAttributedString) {
objc_setAssociatedObject(self, &OriginTextKey, text, .OBJC_ASSOCIATION_RETAIN)
}
private func getOriginText() -> NSAttributedString {
guard let object = objc_getAssociatedObject(self, &OriginTextKey) as? NSAttributedString else {
return NSAttributedString(string: "")
}
return object
}
private func setTimer(_ timer: Timer) {
objc_setAssociatedObject(self, &TimerKey, timer, .OBJC_ASSOCIATION_RETAIN)
}
private func getTimer() -> Timer {
guard let object = objc_getAssociatedObject(self, &TimerKey) as? Timer else {
return Timer()
}
return object
}
private func setEndless(_ endless: Bool) {
objc_setAssociatedObject(self, &EndlessKey, endless, .OBJC_ASSOCIATION_RETAIN)
}
private func getEndless() -> Bool {
guard let object = objc_getAssociatedObject(self, &EndlessKey) as? Bool else {
return false
}
return object
}
private func setTimerStarted(_ timerStarted: Bool) {
objc_setAssociatedObject(self, &TimerStartedKey, timerStarted, .OBJC_ASSOCIATION_RETAIN)
}
private func getTimerStarted() -> Bool {
guard let object = objc_getAssociatedObject(self, &TimerStartedKey) as? Bool else {
return false
}
return object
}
}
@fitsyu
Copy link

fitsyu commented Apr 25, 2020

Line 70 now needs to be: RunLoop.main.add(timer, forMode: .common).
Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment