I have looked at the libraries like gauge kit but they does not solve my problem. Are there any other libraries for making gauge view as in the image? If not, then how can I go around about it?
I Checked these articles and the Libraries
https://medium.com/ajay-bhanushali/create-gaugeview-speedometer-in-swift-571ff97d1a68 (It does not give a label)
Libraries - (GaugeView, ABGaugeViewKit, WMGaugeView, AnyChart for iOS etc) - sectionsGapValue is different in my case
So I am stuck out in between the actual gauge.
You should create your custom UIControl (make it IBDesignable). And draw it in
override func draw(_ rect: CGRect) { }
This tutorial should help you.
Detailed code to draw the text along a circular path, in this SO post : Draw text along circular path in Swift for iOS
I am fairly new to iOS Development and I have a question, where the internet couldn't help me.
At first, I want to have a canvas, where I can draw rects, circles, lines, etc. I already tried the 'workaround' with the image view, but I don't think, that this is a clean solution and it's really not that efficient.
Secondly, is there any function, which gets called every frame? Currently I have a timer which calls a function every 1/60 second, but I've read, that this also isn't very efficient.
Thanks for any response in advance!
If I understand you correctly, you want a canvas with animation support on iOS?
1.need a canvas? a UIView and its sub class is simply a canvas,you can draw shapes in draw method
override func draw(_ rect: CGRect) {
}
2.you want to implement fancy animation on canvas? search CALayer Animation on google and you will get tons of resources teaching you how.Not like other canvas animation,you do not have to use a timer to draw frame animation on iOS.
I am working on an app, with UISlider and need to make it circular.
Is it possible via some native code, or does a 3rd party library have to be integrated?
I want to fill color as user will slider over slider.
You can find 3rd party libraries for circular slider.
Take a look into these:
https://www.cocoacontrols.com/controls/uicircularslider
https://github.com/thomasfinch/Circular-UISlider
https://github.com/milianoo/CurvySlider
I came across this question in a seperate thread with multiple links and didn't like any of the answers offered so I thought I would add my own in what seemed to be the most relevant thread, on the off chance someone else finds their way here and likes the option I provide.
it is not elegant or simple but it is easy and I thought it would be a nice starting point for others to develop their own.
in this example the circular uiScroller is placed on a view (or HUD) that is presented over the top of an SKView. I then use a hitTest to transfer any touches from the gameScene to the UIView and use _touchesBegan and _touchesMoved to update a series of buttons that are hidden like so:
the arrows are all hidden but we use the frames of each box to register where the touch is
I made the arrows UIButtons so it was easier to use the storyboard but I think an imageView works fine as we are only checking the frame of the arrow inside _touchesBegan and then sending it to the function rather than collection a touch event from the arrow itself.
if upBtn.frame.contains(touch) {
upBtnPress() //if you made this a touch func like me a call to (self) as the sender may be required
}
the black circle itself remains visible so it looks like this is where your taps are going.
then finally you create multiple images like this:
any circular pattern for each location possible is appropriate
(I had a total of 16 points for mine)
and then under any press function you just change the image of the black circle to show the correct image based on where the touch location is and you're done!
circleDpad.image = UIImage(named: "up")
calculating the angle:
is quite very simple, there are 16 points on my dial so I need to convert this into a possible direction in 1...360
func angleChanged(angle: CGFloat) {
let valueReached = (angle / 16) * 360 // this gives you the angle in degrees, converting any point that's x/16 into x/360
let turret = checkBaseSelect() //this is my personal code
turret?.tAngle = CGFloat(valueReached) * (CGFloat.pi / 180) //this converts degrees to radians and applies it where I want it.
}
despite only having 16 points I found that even without applying animation it looks quite smooth. thanks for reading.
this is a gif of my circular slider in action
This is my first ever guide, if it needs more information (or should be somewhere else) please let me know.
I am trying to create a progress circle for the Apple Watch version of my app. I know that we aren't able to use UIViews (which would make things so much easier!) so I am looking for alternatives.
Basically, I would like to create one of these prototypes:
The way I was hoping to do things was to add the background layers as a normal WKInterfaceImage and then the progress arrow/line on top as a WKInterfaceImage that rotates around the circle based on the percentage calculated.
I have the percentage calculated so basically, what I am looking for is some help with the math code for rotating the arrow.
Does anyone know if this is possible, and could anyone help me out if so? I'm not trying to update the circle while the app is running; it just needs to update when the Watch App launches to correspond with the iOS version.
Thanks!
As of watchOS 3 it is possible to use SpriteKit.
SKShapeNode can draw shapes, so it is possible to create radial rings.
Add a WKInterfaceSKScene to your interface controller in storyboard and hook it up through an outlet.
Set it up in the awake method of the interface controller
override func awake(withContext context: Any?) {
super.awake(withContext: context)
scene = SKScene(size: CGSize(width: 100, height: 100))
scene.scaleMode = .aspectFit
interfaceScene.presentScene(scene)
}
Create a shape node and add it to the scene
let fraction: CGFloat = 0.75
let path = UIBezierPath(arcCenter: .zero,
radius: 50,
startAngle: 0,
endAngle: 2 * .pi * fraction,
clockwise: true).cgPath
let shapeNode = SKShapeNode(path: path)
shapeNode.strokeColor = .blue
shapeNode.fillColor = .clear
shapeNode.lineWidth = 4
shapeNode.lineCap = .round
shapeNode.position = CGPoint(x: scene.size.width / 2, y: scene.size.height / 2)
scene.addChild(shapeNode)
Another solution is to create 100 picture, for each number you have a frame. So, doing that, you can show an animation using 'startAnimatingWithImagesInRange:duration:repeatCount' method.
The problem is that it's hard to customise each frame. Somebody thought about this issue and created a generator. You can find it by this name:
Radial Bar Chart Generator
This link should help you to customise the frames: http://hmaidasani.github.io/RadialChartImageGenerator/
Also you have same samples on git link.
For 100 frames with a single arc frame you get around 1,8 MB on disk.
Most of what is available on iOS is not present (yet) in WatchKit. In particular, several of the things you want to do are almost impossible. (Glimmer of hope in a moment). In particular, you cannot rotate an image. Or rather, you can rotate an image, but you have to do it on the phone and then pass that image up to the watch at runtime. Also, you cannot easily composite images - however, there is a way to do it.
One way would be to construct the entire rotated, composited image the way you want it on the phone and pass the final data up to the button using [WKInterfaceButton setBackgroundImage:]. Unfortunately, you will likely find this to be slow in the simulator, and most likely it will work poorly on the actual watch. Hard to know for sure because we don't have one, but this is sending the image on the fly over Bluetooth. So you won't get smooth animation or good response times.
A better way is to hack your way to it on the watch. This relies on two tricks: one, layering groups together with background images. Two, using -[WKInterfaceImage startAnimatingWithImagesInRange:duration:repeatCount:].
For the first trick, drop a Group into your layout, then put another group inside it, then (possibly) a button inside that. Then use -[WKInterfaceGroup setBackgroundImage:] and the images will composite together. Make sure you use proper transparency, etc.
For the second trick, refer to the official documentation - essentially, you will need a series of images, one for each possible rotation value, as erdekhayser said. Now, this may seem egregious (it is) and possibly impractical (it is not). This is actually how Apple recommends creating spinners and the like - at least for now. And, yes, that may mean generating 360 different images, although because of the small screen, my advice is to go every 3-5 degrees or so (nobody will be able to tell the difference).
Hope this helps.
Nobody posts code??? Here it is! enjoy:
1) Create the images here: http://hmaidasani.github.io/RadialChartImageGenerator/
2) Drag n Drop a picker into your View Controller, and link it to some viewController.swift file. Set the Picker style to "Sequence" on the menu that appears on the right.
3) Add this code to the viewController.swift , and connect the picker to the IBOutlet and the IBAction:
import WatchKit
import Foundation
class PickerViewController: WKInterfaceController {
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
}
#IBOutlet var itemPicker: WKInterfacePicker!
override func willActivate() {
super.willActivate()
let pickerItems: [WKPickerItem] = (0...100).map {
let pickerItem = WKPickerItem()
pickerItem.contentImage = WKImage(imageName: "singleArc\($0).png")
return pickerItem
}
itemPicker.setItems(pickerItems)
}
#IBAction func pickerSelectedItemChanged(value: Int) {
NSLog("Sequence Picker: \(value) selected.")
}
override func didDeactivate() {
super.didDeactivate()
}
}
WKInterface classes are not able to be subclassed. Therefore, a custom control is not possible.
Also, animation is limited. In order to create an animation, you must store every single frame as an image. Then, you can have an image view in your WatchKit app that cycles through these images.
Store the images in the Images.xcassets folder in the watch target, and try to mess around with the changing the frame based on the percentage the activity is finished.
One extra note: having 100 images would not be efficient, as each WatchKit app has only a limited amount of space on the watch it can take up (I believe it is 20MB, but I am not sure). Maybe have an image for every 5%.
No, there is not possible to creating this custom circle on watch kit, because UIView doesn't work on watch kit.
there is only solution of your problem is you have to put 100 images of each frames... and make sure that size of images is lesser than 20 MB. because the size of watch application is up to 20 MB
I'm working on an app that lets the user stack graphics on top of each other.
The graphics are instantiated as a UIImageView, and is transparent outside of the actual graphic. I'm also using pan gestures to let the user drag them around the screen.
So when you have a bunch of graphics of different sizes and shapes on top of one another, you may have the illusion that you are touching a sub-indexed view, but you're actually touching the top one because some transparent part of it its hovering over your touch point.
I was wondering if anyone had ideas on how we could accomplish ONLY listening to the pan gesture on the solid part of the imageview. Or something that would tighten up the user experience so that whatever they touched was what they select. Thanks
Create your own subclass of UIImageView. In your subclass, override the pointInside:withEvent: method to return NO if the point is in a transparent part of the image.
Of course, you need to determine if a point is in a transparent part. :)
If you happen to have a CGPath or UIBezierPath that outlines the opaque parts of your image, you can do it easily using CGPathContainsPoint or -[UIBezierPath containsPoint:].
If you don't have a handy path, you will have to examine the image's pixel data. There are many answers on stackoverflow.com already that explain how to do that. Search for get pixel CGImage or get pixel UIImage.