How can I make a vertical slider in swift? - swift

I was wondering how I can create a vertical slider in swift.
I have tried using .transform and then adding a rotate but this returned an exception and rotated the whole screen. I just need a vertical slider.
I was wondering if anyone know of a way to rotate a slider in swift?
Thanks

Assuming you are talking about UISlider :
You were looking in a right direction but probably applied AffineTransformation to the wrong item... You should use UISlider.transform to change it orientation.
Here is working code (I did add UISlider using InterfaceBuilder):
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var verticalSlider: UISlider!{
didSet{
verticalSlider.transform = CGAffineTransform(rotationAngle: CGFloat(-M_PI_2))
}
}
}

Options 1:
In Swift 4:
-M_PI_2 is deprecated so Use Double.pi / 2
verticalSlider.transform = CGAffineTransform(rotationAngle: CGFloat(-Double.pi / 2))
OR
Options 2: for All Objective C and Swift
Key path = layer.transform.rotation.z
Type = String
Value = -1.570795
Most Imp Note: before and After keypath No Space

Use OOP. If you define this rotation as an Extension on UIView, then not only the UIView but also all subclasses that inherit from UIView can be rotated. This of course includes UISlider, but also UILabel, UIButton and about 200? other subclasses... see here
list of subclasses for UIView
extension UIView
{
func makeVertical()
{
transform = CGAffineTransform(rotationAngle: -CGFloat.pi / 2)
}
}
// usage example:
sldBoilerTemperature.makeVertical()
It's good to be aware of inheritance, saves a lot of work. For many Swift extensions to make, it might be a good idea trying to move it upwards in the class hierarchy, like in this example.

Swift-5 Vertical slider with constraints
func transformSlider(){
var constraints = [NSLayoutConstraint]()
ControlSlider.transform = CGAffineTransform(rotationAngle: CGFloat(-Double.pi/2))
ControlSlider.translatesAutoresizingMaskIntoConstraints = false
constraints.append(ControlSlider.widthAnchor.constraint(equalTo: self.heightAnchor, multiplier: 0.8))
constraints.append(ControlSlider.centerYAnchor.constraint(equalTo: self.centerYAnchor))
let sliderWidth = (ControlSlider.frame.height * 0.8)/2
print(sliderWidth)
constraints.append(ControlSlider.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: (20-sliderWidth)))
NSLayoutConstraint.activate(constraints)
}

Related

How can I implement this UICollectionView cell animation?

I've been wanting to implement this nice little UICollectionViewCell animation shown below that was on Dribble.
Do you think it's possible?
I looked around for any guides to get a head start on this but found nothing quite similar.
I have the idea that a custom flow layout is the way to go here. Would it be that I will have to make snapshots of each visible cell, add pan gestures to each cell and based on the movement detected through the gesture recogniser, capture visible cells and animate the snapshot images? Would appreciate any help to understand how I could implement this.
Thank you.
This is a pretty interesting challenge.
Instead of doing a custom layout, I would override scrollViewDidScroll, store the offset every time it's called, compare it with the last stored offset in order to get the velocity, and based off of that, apply a transform to all visibleCells in your collection view.
var lastOffsetX: CGFloat?
func scrollViewDidScroll(_ scrollView: UIScrollView) {
defer { lastOffsetX = scrollView.contentOffset.x }
guard let lastOffsetX = lastOffsetX else { return }
// You'll have to evaluate how large velocity gets to avoid the cells
// from stretching too much
let maxVelocity: CGFloat = 60
let maxStretch: CGFloat = 10
let velocity = min(scrollView.contentOffset.x - lastOffsetX, maxVelocity)
let stretch = velocity / maxVelocity * maxStretch
var cumulativeStretch: CGFloat = 0
collectionView.visibleCells.forEach { cell in
cumulativeStretch += stretch
cell.transform = CGAffineTransform(translateX: cumulativeStretch, y: 0)
}
}
I would start with something like this, and make lastOffsetX = nil when the scroll view stops scrolling (this exercise is left to the reader).
It will probably require some tweaking.

How to remove the space between UISlider and Minimum Image

I would like to remove the space / offset at the beginning of the UISlider and join it with the custom minimum image that I have.
Is it possible to do it programmatically in Swift?
I have checked this, but it's old and it's for Objective-C.
well, I looked at the answer you tagged, and made something up for you on playground. Not sure if it works precisely for your case, but the key is to look into the methods of UISlider that you can override here
import UIKit
class SomeController: UIViewController {
let slider = MyCustomSlider()
//etc...
}
class MyCustomSlider: UISlider {
override func maximumValueImageRect(forBounds bounds: CGRect) -> CGRect {
var r = super.maximumValueImageRect(forBounds: bounds)
r.origin.x -= 3
return r
}
}

Consistent curves with dynamic corner radius (Swift)?

Is there a way to make the corner radius of a UIView adept to the view it belongs to? I'm not comfortable with the idea of hard-coding corner radius values, because as soon as the width or the height of your view changes (on different screen orientations for example), the corners will look totally different. For example, take a look at WhatsApp's chat window.
As you can see, every message container view has a different width and a different height, but the curve of the corners are all exactly the same. This is what I'm trying to achieve. I want the curves of my corners to be the same on every view, no matter what the size of the view is or what screen the view is displayed on. I've tried setting the corner radius relative to the view's height (view.layer.cornerRadius = view.frame.size.height * 0.25) and I've also tried setting it to the view's width, but this doesn't work. The corners still look weird as soon as they are displayed on a different screen size. Please let me know if there's a certain formula or trick to make the curves look the same on every view/screen size.
Here's the best I can do. I don't know if this will be of help, but hopefully it will give you some ideas.
First the code:
class ViewController: UIViewController {
let cornerRadius:CGFloat = 10
let insetValue:CGFloat = 10
var numberOfViews:Int = 0
var myViews = [UIView]()
override func viewDidLoad() {
super.viewDidLoad()
view.translatesAutoresizingMaskIntoConstraints = false
}
override func viewWillLayoutSubviews() {
setNumberOfViews()
createViews()
createViewHierarchy()
addConstraints()
}
func setNumberOfViews() {
var smallerDimension:CGFloat = 0
if view.frame.height < view.frame.width {
smallerDimension = view.frame.height
} else {
smallerDimension = view.frame.width
}
let viewCount = smallerDimension / (insetValue * 2)
numberOfViews = Int(viewCount)
}
func createViews() {
for i in 1...numberOfViews {
switch i % 5 {
case 0:
myViews.append(MyView(UIColor.black, cornerRadius))
case 1:
myViews.append(MyView(UIColor.blue, cornerRadius))
case 2:
myViews.append(MyView(UIColor.red, cornerRadius))
case 3:
myViews.append(MyView(UIColor.yellow, cornerRadius))
case 4:
myViews.append(MyView(UIColor.green, cornerRadius))
default:
break
}
}
}
func createViewHierarchy() {
view.addSubview(myViews[0])
for i in 1...myViews.count-1 {
myViews[i-1].addSubview(myViews[i])
}
}
func addConstraints() {
for view in myViews {
view.topAnchor.constraint(equalTo: (view.superview?.topAnchor)!, constant: insetValue).isActive = true
view.leadingAnchor.constraint(equalTo: (view.superview?.leadingAnchor)!, constant: insetValue).isActive = true
view.trailingAnchor.constraint(equalTo: (view.superview?.trailingAnchor)!, constant: -insetValue).isActive = true
view.bottomAnchor.constraint(equalTo: (view.superview?.bottomAnchor)!, constant: -insetValue).isActive = true
}
}
}
class MyView: UIView {
convenience init(_ backgroundColor:UIColor, _ cornerRadius:CGFloat) {
self.init(frame: CGRect.zero)
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = backgroundColor
self.layer.cornerRadius = cornerRadius
}
}
Explanation:
This is fairly simple code. The intent was to create as deeply nested a view hierarchy as possible, and, using auto layout, have two main variables: cornerRadius (the view's corner radius) and insetValue (the "frame's" inset). These two variables can be adjusted for experimenting.
The bulk of the logic is in viewWillLayoutSubviews, where the root view frame size is know. Since I'm using 5 different background colors, I'm calculating how many views can fit in the hierarchy. Then I'm creating them, followed by creating the view hierarchy, and finally I'm adding the constraints.
Experimenting and conclusions:
I was able to see what your concern is - yes, if a view's size components are smaller than the corner radius, you end up with inconsistent looking corners. But these values are pretty small - pretty much 10 or less. Most views are unusable at that size. (If I recall even the HIG suggests that a button should be no less than 40 points in size. Sure, even Apple breaks that rule. Still.)
If your 'insetValueis sufficiently larger than the corner radius, you should never have an issue. Likewise, using the iMessage scenario, a singleUILabelcontaining text and/or emoticons should have enough height that a noticeablecornerRadius` can be had.
The key point to set things like cornerRadius and insetValue is in viewWillLayoutSubviews, when you can decide (1) which is the smaller dimension, height or width, (2) how deeply you can nest views, and (3) how large of a corner radius you can set.
Use auto layout! Please note the absolute lack of frames. Other than determining the root view's dimensions at the appropriate time, you can write very compact code without worrying about device size or orientation.

NSView and Swift 3.0

I have finally upgraded to Swift 3.0 and encountered a problem - I'm using custom view and its drawrect function to render some drawing, and I override 'isFlipped' var to return true and draw them upside down. Before Swift 3.0 it works like a charm but now Cocoa turns upside down not only this particular drawing but also any other my subviews (which I don't want to have this way). Does anyone know how to fix this?
I didn't figure out how to return back 'isFlipped' var behavior from Swift 2 so instead I simply rotate coordinates of all my subviews. It could be done like this:
override func viewWillAppear() {
for child in self.view.subviews {
child.frame = NSRect.init(
x: child.frame.minX,
y: self.view.frame.height - child.frame.minY - child.frame.height,
width: child.frame.width,
height: child.frame.height)
}
}

How To Implement A Circular Loader without SKShapeNode

I want to creat a simple circular loader animation circle and border around it which is disappearing
I found great frameworks but they use SKShapeNode and SKShapeNode performance is terrible for actual deployed app
ProgressNode: Very cool framework
You could use a UIView within a UIImageView with a "loading circle" as image and just let rotate it. Here is a example class:
import UIKit
class CircularLoadingView: UIView {
#IBOutlet weak var rotatingImage: UIImageView!
let duration: Double = 1
func startAnimation() {
let animation = CABasicAnimation(keyPath: "transform.rotation.z")
animation.toValue = NSNumber(floatLiteral: M_PI * 2.0 * duration)
animation.duration = duration
animation.isCumulative = true
animation.repeatCount = Float(CGFloat.greatestFiniteMagnitude)
rotatingImage.layer.add(animation, forKey: "animationKey")
UIView.animate(withDuration: duration, animations: {
self.alpha = 1
})
}
}
Just add a UIView and set CircularLoadingView as custom class. Add a UIImageView, set the image you want to rotate, set the outlets and constraints and see what happens.
But with this attempt you need an image, which you have to create or to find.
If this does not help you, perhaps this old raywenderlich tutorial can. There they show how to make a circular indicator with CAShapeLayer.