parent
2d830d4c82
commit
8e446b1c93
19
README.md
19
README.md
|
|
@ -22,10 +22,11 @@ Ideal to select individual steps, star rating, integers, rainbow colors, slices
|
|||
Ideal to represent steps. *The discrete slider and the camel labels can work in unison.*
|
||||
|
||||
## Compatibility
|
||||
1. Written in **Swift 3**, can be integrated with **Swift** or **Obj-C**
|
||||
1. Written in **Swift 4**, can be integrated with **Swift** or **Obj-C**
|
||||
2. `TGPControls` are **AutoLayout**, `IB Designable` and `IB Inspectable` ready
|
||||
3. Version **5.0.1** comes with a **Swift 4** demo application for **iOS 8** and above.
|
||||
3. Version **5.0.1** and better comes with a **Swift 4** demo application for **iOS 8** and above.
|
||||
_**iOS 7** supported in versions 2.1.0 and earlier_
|
||||
4. Automatic support for both left-to-right and right-to-left languages
|
||||
|
||||

|
||||
|
||||
|
|
@ -82,7 +83,9 @@ All graphic aspects, such as physical spacing of the ticks or physical width of
|
|||
```
|
||||
discreteSlider.ticksListener = camelLabels
|
||||
```
|
||||
|
||||

|
||||
|
||||
That's all!
|
||||
Through the `TGPControlsTicksProtocol`, the camelLabels listen to _value_ and _size_ changes. You may want to adopt this protocol to handle changes, or use the traditional `UIControl` notifications:
|
||||
|
||||
|
|
@ -118,13 +121,16 @@ self.stepper.value = Double(sender.value)
|
|||
|
||||
| Tick | |
|
||||
|:-----| ----- |
|
||||
| `tickStyle` | See style property |
|
||||
| `tickSize` | absolute dimension |
|
||||
| `tickImage` | a `UIImage`, fits in `tickSize` (†) |
|
||||
| `tickCount` | discrete steps, must be 2 or greater |
|
||||
| `tickTintColor` | takes precedence over the control `tintColor` |
|
||||
| `tickImage` | a `UIImage`, fits in `tickSize` (†) |
|
||||
| `ticksDistance` | horizontal spacing _(calculated)_ |
|
||||
|
||||
| Track | |
|
||||
|:------| ----- |
|
||||
| `trackStyle` | See style property |
|
||||
| `trackThickness` | height |
|
||||
| `trackImage` | a `UIImage`, ignores `trackThickness` (†) |
|
||||
| `minimumTrackTintColor` | track lower side |
|
||||
|
|
@ -132,9 +138,10 @@ self.stepper.value = Double(sender.value)
|
|||
|
||||
| Thumb | |
|
||||
|:------| ----- |
|
||||
| `thumbStyle` | See style property |
|
||||
| `thumbSize` | absolute size |
|
||||
| `thumbImage` | a`UIImage`, dictates `thumbSize` (†) |
|
||||
| `thumbTintColor` | background |
|
||||
| `thumbImage` | a`UIImage`, dictates `thumbSize` (†) |
|
||||
| `thumbShadowRadius` | breaking the _flat design concept_ |
|
||||
| `thumbShadowOffset` | applied to `thumbShadowRadius`, may affect control bounds |
|
||||
|
||||
|
|
@ -159,8 +166,9 @@ Most of the customization can be done inside **Interface Builder**.
|
|||
|
||||
| Property | |
|
||||
|:---------| ----- |
|
||||
| `ticksListener` | ties a discrete slider to its camel labels. This is your most robust method to not only ensure that the layout of both controls match exactly, but also adjust this spacing when orientation changes. A typical use may be `discreteSlider.ticksListener = camelLabels` |
|
||||
| `tickCount` | **design only** (_preferrably not to be used_): the number of ticks is driven by the number of elements in the `names` array |
|
||||
| `names` | supplies a new set of labels ; supersedes the `tickCount` property, which will return the number of labels. A typical use may be `camelLabels.names = ["OFF", "ON"]` |
|
||||
| `ticksListener` | ties a discrete slider to its camel labels. This is your most robust method to not only ensure that the layout of both controls match exactly, but also adjust this spacing when orientation changes. A typical use may be `discreteSlider.ticksListener = camelLabels` |
|
||||
| `ticksDistance` | _override_ the labels spacing entirely ; **prefer** the `ticksListener` mechanism if it is available to you. A typical use may be `camelLabels.ticksDistance = 15` |
|
||||
| `value` | which label is emphasized (_selected_) |
|
||||
| `backgroundColor` | labels become *tap-through* (**click-through**) when set to `UIColor.clear` ; use TGPCamelLabels *on top of* other UI elements, **even native iOS objects**!(*) |
|
||||
|
|
@ -170,6 +178,7 @@ Most of the customization can be done inside **Interface Builder**.
|
|||
|
||||
| Edges & Animation | |
|
||||
|:------------------| ----- |
|
||||
| `numberOfLiness` | Support for multiple lines labels |
|
||||
| `offCenter` | **leftmost and righmost labels only**: relative inset expressed as a proportion of individual label width: 0: none, +0.5: nudge in by a half width (fully fit) or -0.5: draw completely outside |
|
||||
| `insets` | **leftmost and righmost labels only**: absolute inset expressed in pixels |
|
||||
| `emphasisLayout` | emphasized (_selected_) labels vertical alignment ; `.top`, `.centerY` or `.bottom`. Default is `.top` (‡) |
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ Pod::Spec.new do |spec|
|
|||
|
||||
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
|
||||
spec.name = "TGPControls"
|
||||
spec.version = "5.0.2"
|
||||
spec.version = "5.0.3"
|
||||
spec.summary = "Custom animated iOS controls: Animated discrete slider, animated labels"
|
||||
|
||||
spec.description = <<-DESC
|
||||
|
|
@ -26,7 +26,7 @@ Pod::Spec.new do |spec|
|
|||
spec.swift_version = '4.0'
|
||||
|
||||
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
|
||||
spec.source = { :git => "https://github.com/SwiftArchitect/TGPControls.git", :tag => "v5.0.2" }
|
||||
spec.source = { :git => "https://github.com/SwiftArchitect/TGPControls.git", :tag => "v5.0.3" }
|
||||
spec.source_files = "TGPControls/**/*.{swift}"
|
||||
spec.exclude_files = "TGPControlsDemo/*"
|
||||
|
||||
|
|
|
|||
|
|
@ -78,11 +78,11 @@ public class TGPCamelLabels: TGPCamelLabels_INTERFACE_BUILDER {
|
|||
}
|
||||
}
|
||||
|
||||
@IBInspectable public var numberOfLinesInLabel:Int = 1 {
|
||||
didSet {
|
||||
layoutTrack()
|
||||
}
|
||||
}
|
||||
@IBInspectable public var numberOfLinesInLabel:Int = 1 {
|
||||
didSet {
|
||||
layoutTrack()
|
||||
}
|
||||
}
|
||||
|
||||
// Label off-center to the left and right of the slider
|
||||
// expressed in label width. 0: none, -1/2: half outside, 1/2; half inside
|
||||
|
|
@ -166,6 +166,7 @@ public class TGPCamelLabels: TGPCamelLabels_INTERFACE_BUILDER {
|
|||
var lastValue = NSNotFound
|
||||
var emphasizedLabels:[UILabel] = []
|
||||
var regularLabels:[UILabel] = []
|
||||
var localeCharacterDirection = CFLocaleLanguageDirection.leftToRight
|
||||
|
||||
// MARK: UIView
|
||||
|
||||
|
|
@ -195,6 +196,11 @@ public class TGPCamelLabels: TGPCamelLabels_INTERFACE_BUILDER {
|
|||
// MARK: TGPCamelLabels
|
||||
|
||||
func initProperties() {
|
||||
if let systemLocale = CFLocaleCopyCurrent(),
|
||||
let localeIdentifier = CFLocaleGetIdentifier(systemLocale) {
|
||||
localeCharacterDirection = CFLocaleGetLanguageCharacterDirection(localeIdentifier.rawValue)
|
||||
}
|
||||
|
||||
debugNames(count: 10)
|
||||
layoutTrack()
|
||||
}
|
||||
|
|
@ -234,10 +240,16 @@ public class TGPCamelLabels: TGPCamelLabels_INTERFACE_BUILDER {
|
|||
let count = names.count
|
||||
if count > 0 {
|
||||
var centerX = (bounds.width - (CGFloat(count - 1) * ticksDistance))/2.0
|
||||
if .rightToLeft == localeCharacterDirection {
|
||||
centerX = bounds.width - centerX
|
||||
}
|
||||
let tickSpacing = (.rightToLeft == localeCharacterDirection)
|
||||
? -ticksDistance
|
||||
: ticksDistance
|
||||
let centerY = bounds.height / 2.0
|
||||
for name in names {
|
||||
let upLabel = UILabel.init()
|
||||
upLabel.numberOfLines = self.numberOfLinesInLabel
|
||||
upLabel.numberOfLines = numberOfLinesInLabel
|
||||
emphasizedLabels.append(upLabel)
|
||||
upLabel.text = name
|
||||
if let upFontName = upFontName {
|
||||
|
|
@ -261,7 +273,7 @@ public class TGPCamelLabels: TGPCamelLabels_INTERFACE_BUILDER {
|
|||
addSubview(upLabel)
|
||||
|
||||
let dnLabel = UILabel.init()
|
||||
dnLabel.numberOfLines = self.numberOfLinesInLabel
|
||||
dnLabel.numberOfLines = numberOfLinesInLabel
|
||||
regularLabels.append(dnLabel)
|
||||
dnLabel.text = name
|
||||
if let downFontName = downFontName {
|
||||
|
|
@ -279,15 +291,21 @@ public class TGPCamelLabels: TGPCamelLabels_INTERFACE_BUILDER {
|
|||
}()
|
||||
addSubview(dnLabel)
|
||||
|
||||
centerX += ticksDistance
|
||||
centerX += tickSpacing
|
||||
}
|
||||
|
||||
// Fix left and right label, if there are at least 2 labels
|
||||
if names.count > 1 {
|
||||
insetLabel(emphasizedLabels.first, withInset: insets, andMultiplier: offCenter)
|
||||
insetLabel(emphasizedLabels.last, withInset: -insets, andMultiplier: -offCenter)
|
||||
insetLabel(regularLabels.first, withInset: insets, andMultiplier: offCenter)
|
||||
insetLabel(regularLabels.last, withInset: -insets, andMultiplier: -offCenter)
|
||||
let localeInsets = (.rightToLeft == localeCharacterDirection)
|
||||
? -insets
|
||||
: insets
|
||||
let localeOffCenter = (.rightToLeft == localeCharacterDirection)
|
||||
? -offCenter
|
||||
: offCenter
|
||||
insetLabel(emphasizedLabels.first, withInset: localeInsets, andMultiplier: localeOffCenter)
|
||||
insetLabel(emphasizedLabels.last, withInset: -localeInsets, andMultiplier: -localeOffCenter)
|
||||
insetLabel(regularLabels.first, withInset: localeInsets, andMultiplier: localeOffCenter)
|
||||
insetLabel(regularLabels.last, withInset: -localeInsets, andMultiplier: -localeOffCenter)
|
||||
}
|
||||
|
||||
dockEffect(duration:0.0)
|
||||
|
|
|
|||
|
|
@ -208,7 +208,6 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
let segments = CGFloat(max(1, tickCount - 1))
|
||||
return trackRectangle.width / segments
|
||||
}
|
||||
set {}
|
||||
}
|
||||
|
||||
@objc public var ticksListener:TGPControlsTicksProtocol? = nil {
|
||||
|
|
@ -221,15 +220,18 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
var intValue:Int = 0
|
||||
var intMinimumValue = -5
|
||||
|
||||
var ticksAbscisses:[CGPoint] = []
|
||||
var thumbAbscisse:CGFloat = 0
|
||||
var ticksAbscissae:[CGPoint] = []
|
||||
var thumbAbscissa:CGFloat = 0
|
||||
var thumbLayer = CALayer()
|
||||
var leftTrackLayer = CALayer()
|
||||
var rightTrackLayer = CALayer()
|
||||
var trackLayer = CALayer()
|
||||
var leadingTrackLayer: CALayer!
|
||||
var trailingTrackLayer: CALayer!
|
||||
var ticksLayer = CALayer()
|
||||
var trackRectangle = CGRect.zero
|
||||
var touchedInside = false
|
||||
var localeCharacterDirection = CFLocaleLanguageDirection.leftToRight
|
||||
|
||||
let iOSThumbShadowRadius:CGFloat = 4
|
||||
let iOSThumbShadowOffset = CGSize(width:0, height:3)
|
||||
|
|
@ -262,17 +264,30 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
// MARK: TGPDiscreteSlider
|
||||
|
||||
func initProperties() {
|
||||
if let systemLocale = CFLocaleCopyCurrent(),
|
||||
let localeIdentifier = CFLocaleGetIdentifier(systemLocale) {
|
||||
localeCharacterDirection = CFLocaleGetLanguageCharacterDirection(localeIdentifier.rawValue)
|
||||
}
|
||||
|
||||
leadingTrackLayer = (.rightToLeft == localeCharacterDirection)
|
||||
? rightTrackLayer
|
||||
: leftTrackLayer
|
||||
trailingTrackLayer = (.rightToLeft == localeCharacterDirection)
|
||||
? leftTrackLayer
|
||||
: rightTrackLayer
|
||||
|
||||
// Track is a clear clipping layer, and left + right sublayers, which brings in free animation
|
||||
trackLayer.masksToBounds = true
|
||||
trackLayer.backgroundColor = UIColor.clear.cgColor
|
||||
layer.addSublayer(trackLayer)
|
||||
if let backgroundColor = tintColor {
|
||||
leftTrackLayer.backgroundColor = backgroundColor.cgColor
|
||||
}
|
||||
trackLayer.addSublayer(leftTrackLayer)
|
||||
rightTrackLayer.backgroundColor = maximumTrackTintColor.cgColor
|
||||
trackLayer.addSublayer(rightTrackLayer)
|
||||
|
||||
if let backgroundColor = tintColor {
|
||||
leadingTrackLayer.backgroundColor = backgroundColor.cgColor
|
||||
}
|
||||
rightTrackLayer.backgroundColor = maximumTrackTintColor.cgColor
|
||||
|
||||
// Ticks in between track and thumb
|
||||
layer.addSublayer(ticksLayer)
|
||||
|
||||
|
|
@ -300,7 +315,7 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
fallthrough
|
||||
|
||||
case .image:
|
||||
for originPoint in ticksAbscisses {
|
||||
for originPoint in ticksAbscissae {
|
||||
let rectangle = CGRect(x: originPoint.x-(tickSize.width/2),
|
||||
y: originPoint.y-(tickSize.height/2),
|
||||
width: tickSize.width,
|
||||
|
|
@ -391,21 +406,21 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
|
||||
leftTrackLayer.frame = {
|
||||
var frame = trackLayer.bounds
|
||||
frame.size.width = thumbAbscisse - trackRectangle.minX
|
||||
frame.size.width = thumbAbscissa - trackRectangle.minX
|
||||
return frame
|
||||
}()
|
||||
|
||||
if let backgroundColor = minimumTrackTintColor ?? tintColor {
|
||||
leftTrackLayer.backgroundColor = backgroundColor.cgColor
|
||||
}
|
||||
|
||||
rightTrackLayer.frame = {
|
||||
var frame = trackLayer.bounds
|
||||
frame.size.width = trackRectangle.width - leftTrackLayer.frame.width
|
||||
frame.origin.x = leftTrackLayer.frame.maxX
|
||||
return frame
|
||||
}()
|
||||
rightTrackLayer.backgroundColor = maximumTrackTintColor.cgColor
|
||||
|
||||
if let backgroundColor = minimumTrackTintColor ?? tintColor {
|
||||
leadingTrackLayer.backgroundColor = backgroundColor.cgColor
|
||||
}
|
||||
trailingTrackLayer.backgroundColor = maximumTrackTintColor.cgColor
|
||||
}
|
||||
|
||||
func drawThumb() {
|
||||
|
|
@ -414,7 +429,7 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
let thumbSizeForStyle = thumbSizeIncludingShadow()
|
||||
let thumbWidth = thumbSizeForStyle.width
|
||||
let thumbHeight = thumbSizeForStyle.height
|
||||
let rectangle = CGRect(x:thumbAbscisse - (thumbWidth / 2),
|
||||
let rectangle = CGRect(x:thumbAbscissa - (thumbWidth / 2),
|
||||
y: (frame.height - thumbHeight)/2,
|
||||
width: thumbWidth,
|
||||
height: thumbHeight)
|
||||
|
|
@ -515,11 +530,11 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
width: trackSize.width,
|
||||
height: trackSize.height)
|
||||
let trackY = frame.height / 2
|
||||
ticksAbscisses = []
|
||||
ticksAbscissae = []
|
||||
for iterate in 0 ... segments {
|
||||
let ratio = Double(iterate) / Double(segments)
|
||||
let originX = trackRectangle.origin.x + (CGFloat)(trackSize.width * CGFloat(ratio))
|
||||
ticksAbscisses.append(CGPoint(x: originX, y: trackY))
|
||||
ticksAbscissae.append(CGPoint(x: originX, y: trackY))
|
||||
}
|
||||
layoutThumb()
|
||||
|
||||
|
|
@ -536,7 +551,10 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
let nonZeroIncrement = ((0 == incrementValue) ? 1 : incrementValue)
|
||||
var thumbRatio = Double(value - minimumValue) / Double(segments * nonZeroIncrement)
|
||||
thumbRatio = max(0.0, min(thumbRatio, 1.0)) // Normalized
|
||||
thumbAbscisse = trackRectangle.origin.x + (CGFloat)(trackRectangle.width * CGFloat(thumbRatio))
|
||||
thumbRatio = (.rightToLeft == localeCharacterDirection)
|
||||
? 1.0 - thumbRatio
|
||||
: thumbRatio
|
||||
thumbAbscissa = trackRectangle.origin.x + (CGFloat)(trackRectangle.width * CGFloat(thumbRatio))
|
||||
}
|
||||
|
||||
func thumbSizeIncludingShadow() -> CGSize {
|
||||
|
|
@ -628,14 +646,14 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
func touchDown(_ touches: Set<UITouch>, animationDuration duration:TimeInterval) {
|
||||
if let touch = touches.first {
|
||||
let location = touch.location(in: touch.view)
|
||||
moveThumbTo(abscisse: location.x, animationDuration: duration)
|
||||
moveThumbTo(abscissa: location.x, animationDuration: duration)
|
||||
}
|
||||
}
|
||||
|
||||
func touchUp(_ touches: Set<UITouch>) {
|
||||
if let touch = touches.first {
|
||||
let location = touch.location(in: touch.view)
|
||||
let tick = pickTickFromSliderPosition(abscisse: location.x)
|
||||
let tick = pickTickFromSliderPosition(abscissa: location.x)
|
||||
moveThumbToTick(tick: tick)
|
||||
}
|
||||
}
|
||||
|
|
@ -665,14 +683,14 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
func moveThumbTo(abscisse:CGFloat, animationDuration duration:TimeInterval) {
|
||||
func moveThumbTo(abscissa:CGFloat, animationDuration duration:TimeInterval) {
|
||||
let leftMost = trackRectangle.minX
|
||||
let rightMost = trackRectangle.maxX
|
||||
|
||||
thumbAbscisse = max(leftMost, min(abscisse, rightMost))
|
||||
thumbAbscissa = max(leftMost, min(abscissa, rightMost))
|
||||
CATransaction.setAnimationDuration(duration)
|
||||
|
||||
let tick = pickTickFromSliderPosition(abscisse: thumbAbscisse)
|
||||
let tick = pickTickFromSliderPosition(abscissa: thumbAbscissa)
|
||||
let nonZeroIncrement = ((0 == incrementValue) ? 1 : incrementValue)
|
||||
let intValue = Int(minimumValue) + (Int(tick) * nonZeroIncrement)
|
||||
if intValue != self.intValue {
|
||||
|
|
@ -683,11 +701,14 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
|
|||
setNeedsDisplay()
|
||||
}
|
||||
|
||||
func pickTickFromSliderPosition(abscisse: CGFloat) -> UInt {
|
||||
func pickTickFromSliderPosition(abscissa: CGFloat) -> UInt {
|
||||
let leftMost = trackRectangle.minX
|
||||
let rightMost = trackRectangle.maxX
|
||||
let clampedAbscisse = max(leftMost, min(abscisse, rightMost))
|
||||
let ratio = Double(clampedAbscisse - leftMost) / Double(rightMost - leftMost)
|
||||
let clampedAbscissa = max(leftMost, min(abscissa, rightMost))
|
||||
var ratio = Double(clampedAbscissa - leftMost) / Double(rightMost - leftMost)
|
||||
ratio = (.rightToLeft == localeCharacterDirection)
|
||||
? 1.0 - ratio
|
||||
: ratio
|
||||
let segments = max(1, tickCount - 1)
|
||||
return UInt(round( Double(segments) * ratio))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@
|
|||
DC56BDCC1E46DEB900AAD0D9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DC56BDCA1E46DEB900AAD0D9 /* Main.storyboard */; };
|
||||
DC56BDCE1E46DEB900AAD0D9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DC56BDCD1E46DEB900AAD0D9 /* Assets.xcassets */; };
|
||||
DC56BDD11E46DEB900AAD0D9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DC56BDCF1E46DEB900AAD0D9 /* LaunchScreen.storyboard */; };
|
||||
DC7677B820C5C5BA006155F3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC7677B620C5C5BA006155F3 /* Localizable.strings */; };
|
||||
DC7677B920C5C5BA006155F3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC7677B620C5C5BA006155F3 /* Localizable.strings */; };
|
||||
DC7677BD20C5C712006155F3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC7677BB20C5C712006155F3 /* InfoPlist.strings */; };
|
||||
DC7677BE20C5C712006155F3 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DC7677BB20C5C712006155F3 /* InfoPlist.strings */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
|
|
@ -50,6 +54,11 @@
|
|||
DC56BDCD1E46DEB900AAD0D9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
DC56BDD01E46DEB900AAD0D9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
DC56BDD21E46DEB900AAD0D9 /* TGPControlsDemo-Pods-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "TGPControlsDemo-Pods-Info.plist"; sourceTree = "<group>"; };
|
||||
DC7677B720C5C5BA006155F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DC7677BA20C5C5E5006155F3 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DC7677BC20C5C712006155F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
DC7677BF20C5C769006155F3 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
DCEE05AD20C20D650081CD34 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Main.strings; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
|
@ -119,6 +128,8 @@
|
|||
DC56BDCF1E46DEB900AAD0D9 /* LaunchScreen.storyboard */,
|
||||
DC56BDD21E46DEB900AAD0D9 /* TGPControlsDemo-Pods-Info.plist */,
|
||||
DC4FF6511EA2E08C00BBF8E4 /* TGPControlsDemo-Cart-Info.plist */,
|
||||
DC7677B620C5C5BA006155F3 /* Localizable.strings */,
|
||||
DC7677BB20C5C712006155F3 /* InfoPlist.strings */,
|
||||
);
|
||||
path = TGPControlsDemo;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -188,6 +199,7 @@
|
|||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
ar,
|
||||
);
|
||||
mainGroup = DC56BDBA1E46DEB900AAD0D9;
|
||||
productRefGroup = DC56BDC41E46DEB900AAD0D9 /* Products */;
|
||||
|
|
@ -206,8 +218,10 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DC4FF6481EA2E08C00BBF8E4 /* LaunchScreen.storyboard in Resources */,
|
||||
DC7677B920C5C5BA006155F3 /* Localizable.strings in Resources */,
|
||||
DC4FF6491EA2E08C00BBF8E4 /* Assets.xcassets in Resources */,
|
||||
DC4FF64A1EA2E08C00BBF8E4 /* Main.storyboard in Resources */,
|
||||
DC7677BE20C5C712006155F3 /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -216,8 +230,10 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
DC56BDD11E46DEB900AAD0D9 /* LaunchScreen.storyboard in Resources */,
|
||||
DC7677B820C5C5BA006155F3 /* Localizable.strings in Resources */,
|
||||
DC56BDCE1E46DEB900AAD0D9 /* Assets.xcassets in Resources */,
|
||||
DC56BDCC1E46DEB900AAD0D9 /* Main.storyboard in Resources */,
|
||||
DC7677BD20C5C712006155F3 /* InfoPlist.strings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
@ -303,6 +319,7 @@
|
|||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
DC56BDCB1E46DEB900AAD0D9 /* Base */,
|
||||
DCEE05AD20C20D650081CD34 /* ar */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -315,6 +332,24 @@
|
|||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DC7677B620C5C5BA006155F3 /* Localizable.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
DC7677B720C5C5BA006155F3 /* Base */,
|
||||
DC7677BA20C5C5E5006155F3 /* ar */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DC7677BB20C5C712006155F3 /* InfoPlist.strings */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
DC7677BC20C5C712006155F3 /* Base */,
|
||||
DC7677BF20C5C769006155F3 /* ar */,
|
||||
);
|
||||
name = InfoPlist.strings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
|
|
@ -359,6 +394,7 @@
|
|||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
|
|
@ -419,6 +455,7 @@
|
|||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = "$(inherited)";
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
"CFBundleDisplayName" = "TGPControls";
|
||||
"NSHumanReadableCopyright" = "2016 Xavier Schott";
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
"oneTo10Labels.numbers" = "1 2 3 4 5 6 7 8 9 10";
|
||||
"alphabetLabels.letters" = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z";
|
||||
|
||||
"pictureLabels.east" = "orient";
|
||||
"pictureLabels.west" = "occident";
|
||||
"pictureLabels.up" = "zénith";
|
||||
"pictureLabels.down" = "nadir";
|
||||
"pictureLabels.north" = "septentrion";
|
||||
"pictureLabels.south" = "midi";
|
||||
|
||||
"switch1Camel.off" = "OFF";
|
||||
"switch1Camel.on" = "ON";
|
||||
|
||||
"switch2Camel.off" = "O";
|
||||
"switch2Camel.on" = "l";
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>TGPControls</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
|
@ -15,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.0.0</string>
|
||||
<string>5.0.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string>TGPControls</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
|
|
@ -15,7 +17,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>4.0.0</string>
|
||||
<string>5.0.3</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
|
|
|
|||
|
|
@ -18,14 +18,35 @@ class ViewController: UIViewController {
|
|||
@IBOutlet weak var dualColorSlider: TGPDiscreteSlider!
|
||||
@IBOutlet weak var stepper: UIStepper!
|
||||
|
||||
private func localizedStrings(_ key: String) -> [String] {
|
||||
return NSLocalizedString(key, comment: "")
|
||||
.split(separator: " ")
|
||||
.map({ (substring) -> String in
|
||||
return "\(substring)"
|
||||
})
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
alphabetLabels.names = ["A","B","C","D","E","F", "G","H","I","J","K","L","M",
|
||||
"N","O","P","Q","R","S", "T","U","V","W","X","Y","Z"]
|
||||
pictureLabels.names = ["orient", "occident", "zénith", "nadir", "septentrion", "midi"]
|
||||
switch1Camel.names = ["OFF", "ON"]
|
||||
switch2Camel.names = ["O", "l"]
|
||||
oneTo10Labels.names = localizedStrings("oneTo10Labels.numbers")
|
||||
|
||||
alphabetLabels.names = localizedStrings("alphabetLabels.letters")
|
||||
alphabetSlider.tickCount = alphabetLabels.names.count // Number of letters in the given alphabet
|
||||
|
||||
pictureLabels.names = [NSLocalizedString("pictureLabels.east", comment: ""),
|
||||
NSLocalizedString("pictureLabels.west", comment: ""),
|
||||
NSLocalizedString("pictureLabels.up", comment: ""),
|
||||
NSLocalizedString("pictureLabels.down", comment: ""),
|
||||
NSLocalizedString("pictureLabels.north", comment: ""),
|
||||
NSLocalizedString("pictureLabels.south", comment: "")]
|
||||
|
||||
switch1Camel.names = [NSLocalizedString("switch1Camel.off", comment: ""),
|
||||
NSLocalizedString("switch1Camel.on", comment: "")]
|
||||
|
||||
switch2Camel.names = [NSLocalizedString("switch2Camel.off", comment: ""),
|
||||
NSLocalizedString("switch2Camel.on", comment: "")]
|
||||
|
||||
|
||||
// Automatically track tick spacing changes and UIControlEventValueChanged
|
||||
alphabetSlider.ticksListener = alphabetLabels
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
"CFBundleDisplayName" = "مراقبةTGP";
|
||||
"NSHumanReadableCopyright" = "2016 Xavier Schott";
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
"oneTo10Labels.numbers" = "١ ٢ ٣ ٤ ٥ ٦ ٧ ٨ ٩ ١٠";
|
||||
"alphabetLabels.letters" = "ا ب ج د ه و ز ح ط ي ك ل م ن س ع ف ص ق ر ش ت ث خ ذ ض ظ غ";
|
||||
|
||||
"pictureLabels.east" = "الشرق";
|
||||
"pictureLabels.west" = "غرب";
|
||||
"pictureLabels.up" = "إلى فوق";
|
||||
"pictureLabels.down" = "نزولا";
|
||||
"pictureLabels.north" = "شمال";
|
||||
"pictureLabels.south" = "جنوب";
|
||||
|
||||
"switch1Camel.off" = "اطفاء";
|
||||
"switch1Camel.on" = "تشغيل";
|
||||
|
||||
"switch2Camel.off" = "٠";
|
||||
"switch2Camel.on" = "١";
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
/* Class = "UILabel"; text = "Layers and transparency"; ObjectID = "1wG-kf-nie"; */
|
||||
"1wG-kf-nie.text" = "Layers and transparency";
|
||||
|
||||
/* Class = "UILabel"; text = "CamelLabels + Switch"; ObjectID = "A6t-OF-SSy"; */
|
||||
"A6t-OF-SSy.text" = "CamelLabels + Switch";
|
||||
|
||||
/* Class = "UILabel"; text = "Variations"; ObjectID = "XPd-Af-CYy"; */
|
||||
"XPd-Af-CYy.text" = "Variations";
|
||||
|
||||
/* Class = "UILabel"; text = "UIControlActions"; ObjectID = "gID-5d-KDe"; */
|
||||
"gID-5d-KDe.text" = "UIControlActions";
|
||||
|
||||
/* Class = "UILabel"; text = "DiscreteSlider + CamelLabels"; ObjectID = "hED-uQ-kcm"; */
|
||||
"hED-uQ-kcm.text" = "DiscreteSlider + CamelLabels";
|
||||
Loading…
Reference in New Issue