when the level is undefined or out of bounds, show question mark on battery (configurable via noLevelText).

This commit is contained in:
Yonat Sharon 2019-07-10 14:04:38 +03:00
parent 14381b43d6
commit 12e1ff8049
6 changed files with 51 additions and 13 deletions

View File

@ -21,8 +21,8 @@ batteryView.level = 42 // anywhere in 0...100
s.author = { "Yonat Sharon" => "yonat@ootips.org" }
s.social_media_url = "http://twitter.com/yonatsharon"
s.swift_versions = ['4.2', '5.0']
s.swift_version = '4.2'
s.swift_versions = ['4.2', '5.0']
s.platform = :ios, "8.0"
s.requires_arc = true

View File

@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Added
- when the level is undefined or out of bounds, show question mark on battery (configurable via `noLevelText`).
## [1.3.5] - 2019-06-21
### Changed

View File

@ -9,6 +9,8 @@
import UIKit
class BatteryViewController: UIViewController {
@IBOutlet var battery: BatteryView!
override func viewDidLoad() {
super.viewDidLoad()
let bigBattery = BatteryView(frame: view.bounds.insetBy(dx: 60, dy: 120))
@ -38,6 +40,10 @@ class BatteryViewController: UIViewController {
}
}
}
@IBAction func changeBatteryLevel(_ sender: UISlider) {
battery.level = Int(sender.value.rounded())
}
}
@UIApplicationMain

View File

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -30,21 +30,30 @@
</constraints>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="boolean" keyPath="isVertical" value="NO"/>
<userDefinedRuntimeAttribute type="number" keyPath="level">
<integer key="value" value="40"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" red="0.60000002384185791" green="0.40000000596046448" blue="0.20000000298023224" alpha="1" colorSpace="calibratedRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="35" minValue="0.0" maxValue="100" translatesAutoresizingMaskIntoConstraints="NO" id="Kg0-p9-8Sw">
<rect key="frame" x="18" y="561" width="339" height="31"/>
<connections>
<action selector="changeBatteryLevel:" destination="BYZ-38-t0r" eventType="valueChanged" id="siV-5Y-K4j"/>
</connections>
</slider>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="Kg0-p9-8Sw" secondAttribute="trailing" constant="20" symbolic="YES" id="2d1-fr-d7U"/>
<constraint firstItem="Kg0-p9-8Sw" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" constant="20" symbolic="YES" id="3gh-BS-Nev"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="iEh-y5-b3Q" secondAttribute="bottom" constant="20" id="Chp-Dd-o8T"/>
<constraint firstItem="iEh-y5-b3Q" firstAttribute="top" secondItem="Kg0-p9-8Sw" secondAttribute="bottom" constant="16" id="p2x-0w-NLF"/>
<constraint firstItem="iEh-y5-b3Q" firstAttribute="centerX" secondItem="8bC-Xf-vdC" secondAttribute="centerX" id="zui-qd-LGW"/>
</constraints>
</view>
<connections>
<outlet property="battery" destination="iEh-y5-b3Q" id="csU-kd-7tD"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>

View File

@ -32,6 +32,7 @@ batteryView.borderColor = .darkGray
batteryView.highLevelColor = .green
batteryView.lowLevelColor = .red
batteryView.noLevelColor = .gray
batteryView.noLevelText = "?" // shown over battery when the level is undefined or out of bounds
```
**Battery Shape:**
@ -44,7 +45,6 @@ batteryView.terminalWidthRatio = 0.4 // relative to battery width
batteryView.borderWidth = 2.5 // default is batteryLength / 20
batteryView.cornerRadius = 5 // default is batteryLength / 10
```
## Installation

View File

@ -43,9 +43,12 @@ extension Int {
// swiftlint:disable redundant_type_annotation
@IBInspectable open dynamic var highLevelColor: UIColor = UIColor(red: 0.0, green: 0.9, blue: 0.0, alpha: 1) { didSet { layoutFillColor() } }
@IBInspectable open dynamic var lowLevelColor: UIColor = UIColor(red: 0.9, green: 0.0, blue: 0.0, alpha: 1) { didSet { layoutFillColor() } }
@IBInspectable open dynamic var noLevelColor: UIColor = UIColor(red: 0.8, green: 0.8, blue: 0.8, alpha: 1) { didSet { layoutFillColor() } }
@IBInspectable open dynamic var noLevelColor: UIColor = UIColor(white: 0.8, alpha: 1) { didSet { layoutFillColor() } }
// swiftlint:enable redundant_type_annotation
/// label shown over battery when the level is undefined or out of range
@IBInspectable open dynamic var noLevelText: String? = "?"
@IBInspectable open dynamic var borderColor: UIColor = .black {
didSet {
bodyOutline.borderColor = borderColor.cgColor
@ -93,12 +96,13 @@ extension Int {
layoutLevel()
}
// MARK: - Sublayers
// MARK: - Subviews & Sublayers
private var bodyOutline = CALayer()
private var terminalOutline = CALayer()
private var terminalOpening = CALayer()
private var levelFill = CALayer()
public let noLevelLabel = UILabel()
private let bodyOutline = CALayer()
private let terminalOutline = CALayer()
private let terminalOpening = CALayer()
private let levelFill = CALayer()
private func setUp() {
layer.addSublayer(bodyOutline)
@ -107,6 +111,9 @@ extension Int {
layer.addSublayer(terminalOutline)
layer.addSublayer(terminalOpening)
setNeedsLayout()
noLevelLabel.translatesAutoresizingMaskIntoConstraints = false
addSubview(noLevelLabel)
}
// MARK: - Layout
@ -121,6 +128,8 @@ extension Int {
// layout body
bodyOutline.frame = bodyFrame
bodyOutline.borderWidth = borderWidth != 0 ? borderWidth : length / 20
noLevelLabel.center = bodyOutline.center
noLevelLabel.font = noLevelLabel.font.withSize(min(bodyFrame.width, 0.75 * bodyFrame.height))
// layout terminal
let parallelInsetRatio = (1 - terminalWidthRatio) / 2
@ -150,6 +159,9 @@ extension Int {
if level >= 0 && level <= .fullBattery {
let levelInset = (isVertical ? levelFrame.height : levelFrame.width) * CGFloat(.fullBattery - level) / CGFloat(Int.fullBattery)
(_, levelFrame) = levelFrame.divided(atDistance: levelInset, from: direction)
noLevelLabel.text = nil
} else {
noLevelLabel.text = noLevelText
}
levelFill.frame = levelFrame.integral
layoutCornerRadius()
@ -184,3 +196,9 @@ extension UIColor {
return UIColor(hue: h, saturation: s, brightness: b, alpha: a)
}
}
extension CALayer {
var center: CGPoint {
return CGPoint(x: frame.midX, y: frame.midY)
}
}