Compare commits

...

23 Commits

Author SHA1 Message Date
Anton Popkov 1165323ea3 Slider thumb with shadow frame calculation fix 2018-12-10 18:44:27 +03:00
Anton Popkov 918edbd74f TGPDiscreteSlider fix track with image size 2018-12-10 17:27:27 +03:00
Xavier Schott cec613690e Closes #53, maintain Xcode 2018-08-20 18:36:50 -07:00
Xavier Schott 4df95aee04
5.1.0 2018-06-06 16:26:24 -07:00
Xavier Schott b51ea58306 Release version 5.1.0 2018-06-06 14:41:16 -07:00
Xavier Schott 7c75b9bac7 Fixes #26 2018-06-06 14:18:18 -07:00
Xavier Schott 8d016e6e9e Merge branch 'master' into develop 2018-06-06 09:22:47 -07:00
Xavier Schott 20a799d1fa
Update travis.yml 2018-06-04 22:51:50 -07:00
Xavier Schott 2fcb23eb7e Merge branch 'master' into develop 2018-06-04 22:22:12 -07:00
Xavier Schott 8e446b1c93 Fixed #47. Fixed #48 2018-06-04 22:15:27 -07:00
Xavier Schott e6be88798b Merge branch 'develop' of github.com:SwiftArchitect/TGPControls into develop 2018-06-04 18:57:59 -07:00
Xavier Schott 2d63e062e1 TGPDiscreteSlider accessor fix 2018-06-04 18:57:31 -07:00
Xavier Schott 0ab8fee2b1
Version 5.0.3 2018-06-04 18:54:13 -07:00
Xavier Schott 1c634aac0f Fixed #47. Fixed #48 (Automatic support for right-to-left languages) 2018-06-04 17:57:49 -07:00
Xavier Schott 3603e112c4 5.0.1 2018-06-01 15:36:25 -05:00
Xavier Schott 193e19228f Merged PR #35 and PR #44 2018-06-01 15:26:00 -05:00
Xavier Schott 0568b14bb4 Fixes #38. Removed verbose comments 2018-05-31 14:42:28 -07:00
Xavier Schott f943038eab Fixes #37: Interface builder hides the IBInspectable for UIControl, which may cause inconsistencies 2018-05-31 14:10:33 -07:00
Xavier Schott bcc249901a Fixes #26. A way to change (all) ticks color of discrete slider: tickTintColor 2018-05-31 13:41:25 -07:00
Xavier Schott c216edf971 LaunchScreen.storyboard 2018-05-31 12:43:10 -07:00
Xavier Schott 48318ad838 Main.storyboard 2018-05-31 12:27:27 -07:00
Xavier Schott 8638f00488 SWIFT_SWIFT3_OBJC_INFERENCE = Default 2018-05-31 12:13:35 -07:00
Xavier Schott ceced355f2 Xcode 9.4 2018-05-31 11:16:24 -07:00
23 changed files with 333 additions and 124 deletions

View File

@ -1,4 +1,4 @@
language: objective-c
osx_image: xcode8.3
osx_image: xcode9.3
script: xcodebuild clean && xcodebuild build -project TGPControls.xcodeproj -scheme TGPControls CODE_SIGNING_REQUIRED=NO

View File

@ -1,11 +1,12 @@
![Demo Project](TGPControlDemo.gif)
# TGP Controls
[![Build Status](https://travis-ci.org/SwiftArchitect/TGPControls.svg?branch=master)](https://travis-ci.org/SwiftArchitect/TGPControls)
[![CocoaPods](http://img.shields.io/cocoapods/v/TGPControls.svg)](https://cocoapods.org/pods/TGPControls)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg)](https://github.com/Carthage/Carthage)
![MIT License](https://img.shields.io/cocoapods/l/TGPControls.svg)
![Demo Project](TGPControlDemo.gif)
# Slider with _ticks_ & animated Label (Swift)
TGPControls are drop-in replacement of `UISlider` & `UILabel`, with visual preview in **Interface Builder**, single liner instrumentation, smooth animations, simple API, powerful customization.
@ -22,10 +23,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
![imagessliderdemo](https://cloud.githubusercontent.com/assets/4073988/6628373/183c7452-c8c2-11e4-9a63-107805bc0cc4.gif)
@ -82,7 +84,9 @@ All graphic aspects, such as physical spacing of the ticks or physical width of
```
discreteSlider.ticksListener = camelLabels
```
![complete](https://cloud.githubusercontent.com/assets/4073988/5912616/26cf1b0a-a58b-11e4-92f7-f9dbcd53c413.gif)
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,27 +122,33 @@ 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 |
| `minimumTickTintColor` | lower side ticks ; takes precedence over `minimumTrackTintColor` (†1) |
| `maximumTickTintColor` | higher side ticks ; takes precedence over `maximumTrackTintColor` (†1) |
| `tickImage` | a `UIImage`, fits in `tickSize` (†) |
| `ticksDistance` | horizontal spacing _(calculated)_ |
| Track | |
|:------| ----- |
| `trackStyle` | See style property |
| `trackThickness` | height |
| `trackImage` | a `UIImage`, ignores `trackThickness` (†) |
| `trackImage` | a `UIImage`, ignores `trackThickness` (†2) |
| `minimumTrackTintColor` | track lower side |
| `maximumTrackTintColor` | track higher side |
| 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 |
(†) Introduced in version 4.0.0. Former versions used a resource name as a `string`.
(†1) Introduced in 5.1.0.
(†2) Introduced in 4.0.0. Former versions used a resource name as a `string`.
![image](https://cloud.githubusercontent.com/assets/4073988/5910789/e102af28-a572-11e4-9169-b18555e20eab.png)
@ -159,8 +169,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 +181,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` (‡) |
@ -191,7 +203,7 @@ Most of the customization can be done inside **Interface Builder**.
---
### Code example (Swift 3)
### Code example (Swift)
See **TGPControlsDemo** project: `TGPControlsDemo` (Modern Swift syntax + IBInspectable)

View File

@ -2,7 +2,7 @@ Pod::Spec.new do |spec|
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.name = "TGPControls"
spec.version = "5.0.2"
spec.version = "5.1.0"
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.1.0" }
spec.source_files = "TGPControls/**/*.{swift}"
spec.exclude_files = "TGPControlsDemo/*"

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
@ -110,7 +110,7 @@
};
};
buildConfigurationList = DC56BDF71E46EA2000AAD0D9 /* Build configuration list for PBXProject "TGPControls" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 9.3";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
@ -199,7 +199,6 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@ -255,10 +254,10 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
@ -279,8 +278,11 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = TGPControls/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.swiftarchitect.TGPControls;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@ -302,8 +304,11 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = TGPControls/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.swiftarchitect.TGPControls;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;

View File

@ -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)

View File

@ -41,7 +41,13 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
}
}
@IBInspectable public var tickTintColor:UIColor? = nil {
@IBInspectable public var minimumTickTintColor:UIColor? = nil {
didSet {
layoutTrack()
}
}
@IBInspectable public var maximumTickTintColor:UIColor? = nil {
didSet {
layoutTrack()
}
@ -78,7 +84,7 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
}
}
@IBInspectable public var maximumTrackTintColor:UIColor = UIColor(white: 0.71, alpha: 1) {
@IBInspectable public var maximumTrackTintColor = UIColor(white: 0.71, alpha: 1) {
didSet {
layoutTrack()
}
@ -208,7 +214,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 +226,25 @@ 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 trackLayer = CALayer()
var leftTrackLayer = CALayer()
var rightTrackLayer = CALayer()
var trackLayer = CALayer()
var leadingTrackLayer: CALayer!
var trailingTrackLayer: CALayer!
var ticksLayer = CALayer()
var leftTicksLayer = CALayer()
var rightTicksLayer = CALayer()
var leadingTicksLayer: CALayer!
var trailingTicksLayer: CALayer!
var trackRectangle = CGRect.zero
var touchedInside = false
var localeCharacterDirection = CFLocaleLanguageDirection.leftToRight
let iOSThumbShadowRadius:CGFloat = 4
let iOSThumbShadowOffset = CGSize(width:0, height:3)
@ -262,19 +277,38 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
// MARK: TGPDiscreteSlider
func initProperties() {
// Track is a clear clipping layer, and left + right sublayers, which brings in free animation
if let systemLocale = CFLocaleCopyCurrent(),
let localeIdentifier = CFLocaleGetIdentifier(systemLocale) {
localeCharacterDirection = CFLocaleGetLanguageCharacterDirection(localeIdentifier.rawValue)
}
leadingTrackLayer = (.rightToLeft == localeCharacterDirection)
? rightTrackLayer
: leftTrackLayer
trailingTrackLayer = (.rightToLeft == localeCharacterDirection)
? leftTrackLayer
: rightTrackLayer
leadingTicksLayer = (.rightToLeft == localeCharacterDirection)
? rightTicksLayer
: leftTicksLayer
trailingTicksLayer = (.rightToLeft == localeCharacterDirection)
? leftTicksLayer
: rightTicksLayer
// Track and ticks are in 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)
// Ticks in between track and thumb
ticksLayer.masksToBounds = true
ticksLayer.backgroundColor = UIColor.clear.cgColor
layer.addSublayer(ticksLayer)
ticksLayer.addSublayer(rightTicksLayer) // reverse order, left covers right
ticksLayer.addSublayer(leftTicksLayer)
// The thumb is its own CALayer, which brings in free animation
layer.addSublayer(thumbLayer)
@ -285,11 +319,6 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
func drawTicks() {
ticksLayer.frame = bounds
if let tickColor = tickTintColor ?? tintColor {
ticksLayer.backgroundColor = tickColor.cgColor
}
let path = UIBezierPath()
switch tickComponentStyle {
@ -300,7 +329,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,
@ -348,10 +377,35 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
break
}
let maskLayer = CAShapeLayer()
maskLayer.frame = trackLayer.bounds
maskLayer.path = path.cgPath
ticksLayer.mask = maskLayer
leftTicksLayer.frame = {
var frame = ticksLayer.bounds
let tickWidth = (.rightToLeft == localeCharacterDirection)
? -tickSize.width/2
: tickSize.width/2
frame.size.width = tickWidth + thumbAbscissa
return frame
}()
leftTicksLayer.mask = {
let maskLayer = CAShapeLayer()
maskLayer.frame = ticksLayer.bounds
maskLayer.path = path.cgPath
return maskLayer
}()
rightTicksLayer.frame = ticksLayer.bounds
rightTicksLayer.mask = {
let maskLayer = CAShapeLayer()
maskLayer.path = path.cgPath
return maskLayer
}()
if let backgroundColor = minimumTickTintColor ?? (minimumTrackTintColor ?? tintColor) {
leadingTicksLayer.backgroundColor = backgroundColor.cgColor
}
trailingTicksLayer.backgroundColor = maximumTickTintColor?.cgColor ?? maximumTrackTintColor.cgColor
}
func drawTrack() {
@ -370,11 +424,7 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
if let image = trackImage,
let cgImage = image.cgImage,
let ctx = UIGraphicsGetCurrentContext() {
let centered = CGRect(x: (frame.width/2) - (image.size.width/2),
y: (frame.height/2) - (image.size.height/2),
width: image.size.width,
height: image.size.height)
ctx.draw(cgImage, in: centered)
ctx.draw(cgImage, in: trackRectangle)
}
case .rounded:
@ -391,21 +441,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,19 +464,13 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
let thumbSizeForStyle = thumbSizeIncludingShadow()
let thumbWidth = thumbSizeForStyle.width
let thumbHeight = thumbSizeForStyle.height
let rectangle = CGRect(x:thumbAbscisse - (thumbWidth / 2),
y: (frame.height - thumbHeight)/2,
width: thumbWidth,
height: thumbHeight)
let shadowRadius = (thumbComponentStyle == .iOS) ? iOSThumbShadowRadius : thumbShadowRadius
let shadowOffset = (thumbComponentStyle == .iOS) ? iOSThumbShadowOffset : thumbShadowOffset
thumbLayer.frame = ((shadowRadius != 0.0) // Ignore offset if there is no shadow
? rectangle.insetBy(dx: shadowRadius + shadowOffset.width,
dy: shadowRadius + shadowOffset.height)
: rectangle.insetBy(dx: shadowRadius,
dy: shadowRadius))
thumbLayer.frame = CGRect(x:thumbAbscissa - (thumbWidth / 2),
y: (frame.height - thumbHeight)/2,
width: thumbWidth,
height: thumbHeight)
switch thumbComponentStyle {
case .rounded: // A rounded thumb is circular
@ -504,22 +548,17 @@ public class TGPDiscreteSlider:TGPSlider_INTERFACE_BUILDER {
let trackHeight = (.iOS == trackComponentStyle) ? 2 : trackThickness
var trackSize = CGSize(width: frame.width - thumbWidth,
height: trackHeight)
if(.image == trackComponentStyle) {
if let image = trackImage {
trackSize.width = image.size.width - thumbWidth
}
}
trackRectangle = CGRect(x: (frame.width - trackSize.width)/2,
y: (frame.height - trackSize.height)/2,
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 +575,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 +670,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 +707,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 +725,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))
}

View File

@ -3,8 +3,23 @@ platform :ios, '8.0'
use_frameworks!
target 'TGPControlsDemo-Pods' do
pod 'TGPControls', :path => '../../TGPControls'
#pod 'TGPControls'
#pod 'TGPControls', :path => '../../TGPControls'
pod 'TGPControls'
end
# Failed to render and update auto layout status for UIViewController : dlopen(Cosmos.framework, 1): no suitable image found
# https://github.com/CocoaPods/CocoaPods/issues/7606#issuecomment-381279098
# https://stackoverflow.com/a/49936237/218152
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings.delete('CODE_SIGNING_ALLOWED')
config.build_settings.delete('CODE_SIGNING_REQUIRED')
end
end
installer.pods_project.build_configurations.each do |config|
config.build_settings.delete('CODE_SIGNING_ALLOWED')
config.build_settings.delete('CODE_SIGNING_REQUIRED')
end
end

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
@ -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>";
@ -153,7 +164,6 @@
DC56BDC01E46DEB900AAD0D9 /* Frameworks */,
DC56BDC11E46DEB900AAD0D9 /* Resources */,
A772C50843047EE677ADAF15 /* [CP] Embed Pods Frameworks */,
3FF2E09CAFA7D92A488FACF7 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@ -182,12 +192,13 @@
};
};
buildConfigurationList = DC56BDBE1E46DEB900AAD0D9 /* Build configuration list for PBXProject "TGPControlsDemo" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 9.3";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
ar,
);
mainGroup = DC56BDBA1E46DEB900AAD0D9;
productRefGroup = DC56BDC41E46DEB900AAD0D9 /* Products */;
@ -206,8 +217,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 +229,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;
};
@ -242,21 +257,6 @@
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3FF2E09CAFA7D92A488FACF7 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-TGPControlsDemo-Pods/Pods-TGPControlsDemo-Pods-resources.sh\"\n";
showEnvVarsInLog = 0;
};
A772C50843047EE677ADAF15 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
@ -303,6 +303,7 @@
isa = PBXVariantGroup;
children = (
DC56BDCB1E46DEB900AAD0D9 /* Base */,
DCEE05AD20C20D650081CD34 /* ar */,
);
name = Main.storyboard;
sourceTree = "<group>";
@ -315,6 +316,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 */
@ -329,7 +348,10 @@
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = "$(SRCROOT)/TGPControlsDemo/TGPControlsDemo-Cart-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.swiftarchitect.TGPControlsDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
@ -347,7 +369,10 @@
"$(PROJECT_DIR)/Carthage/Build/iOS",
);
INFOPLIST_FILE = "$(SRCROOT)/TGPControlsDemo/TGPControlsDemo-Cart-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.swiftarchitect.TGPControlsDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 4.0;
@ -359,6 +384,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 +445,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++";
@ -460,7 +487,8 @@
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
@ -475,7 +503,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/TGPControlsDemo/TGPControlsDemo-Pods-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.swiftarchitect.TGPControlsDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
@ -491,7 +522,10 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/TGPControlsDemo/TGPControlsDemo-Pods-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.swiftarchitect.TGPControlsDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 879 B

After

Width:  |  Height:  |  Size: 810 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,2 @@
"CFBundleDisplayName" = "TGPControls";
"NSHumanReadableCopyright" = "2016 Xavier Schott";

View File

@ -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";

View File

@ -379,6 +379,12 @@
<userDefinedRuntimeAttribute type="size" keyPath="thumbShadowOffset">
<size key="value" width="0.0" height="0.0"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="minimumTickTintColor">
<color key="value" red="0.85098039219999999" green="0.0" blue="0.1058823529" alpha="1" colorSpace="calibratedRGB"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="maximumTickTintColor">
<color key="value" red="0.85098039219999999" green="0.49424107142857143" blue="0.1058823529" alpha="1" colorSpace="calibratedRGB"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="UIControlActions" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gID-5d-KDe">

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -0,0 +1,2 @@
"CFBundleDisplayName" = "مراقبةTGP";
"NSHumanReadableCopyright" = "2016 Xavier Schott";

View File

@ -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" = "١";

View File

@ -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";