Layering transparent images and text on top of a mapView (Swift) - swift

I want to put a transparent box on top of a mapView and then some text on top of that.
I can do this treating the image as a button and altering the alpha setting but only the last UILabel I put in place remains black, the rest are muted.
Is this possible with Tags or something or does it have to be done programatically?
Anyway after a couple of hours sleuthing this is a working solution.
Declare your layer
#IBOutlet weak var layerView: UIView!
var myLayer: CALayer {
return layerView.layer
}
Put a UIView on your ViewController and link it to layerView.
Create a method/func to display the frame, e.g.
func displayMyFrame() {
myLayer.frame = CGRectMake(100, 100, 200, 40)
myLayer.backgroundColor = UIColor.whiteColor().CGColor
myLayer.borderWidth = 1.0
myLayer.borderColor = UIColor.redColor().CGColor
myLayer.shadowOpacity = 0.6
myLayer.cornerRadius = 5.0
myLayer.shadowRadius = 10.0
myLayer.opacity = 0.6
}
Put your UILabels on the view and change their tags to 1 (in this example).
Call the func in viewDidLoad.
displayMyFrame()
view.layer.insertSublayer(myLayer, atIndex: 1)
The atIndex: 1 means that this frame will be put behind the UILabels with a Tag of 1.
This works, hope that it helps.

Related

Getting the View's center when initialing a variable

I'm very new to Swift and trying to make a simple application to learn.
I'm trying to setup on screen a UISlider and set it in the middle of the screen, the problem is that the view is probably isn't ready yet.
I tried to do something like this:
> private let bullsEyeSlider: UISlider = {
> let slider = UISlider(frame: CGRect(x: self.view.frame.midX,y:100, width: 500, height: 20))
> slider.minimumValue = 0
> slider.maximumValue = 100
> return slider
> }()
to get the center of the view (the x center at least) but of course it can't work.
I'm trying to think of something else to do but other than just setting up the slider after the view is initialised I can't think of anything else.
Tried to search the web but with no luck.
In viewDidLayoutSubviews method of the view controller add:
bullsEyeSlider.center = view.center

shadow not behind text

I've made a function that is called in drawRect() inside a seperate made class for a Label. However, this draws only behind the text, and not behind the background of the label. I want to have a shadow behind the background of the label, not the text. How can I fix this? The same happens in a seperate made class for a View.
let COLOR_SHADOW_COLOR: CGColor = UIColor.gray.cgColor
let COLOR_SHADOW_OFFSET = CGSize(width: 2, height: -2)
let COLOR_SHADOW_RADIUS: CGFloat = 5
let COLOR_SHADOW_OPACITY: Float = 1.0
func setShadow(on object: UIView) {
object.layer.shadowColor = COLOR_SHADOW_COLOR
object.layer.shadowOpacity = COLOR_SHADOW_OPACITY
object.layer.shadowOffset = COLOR_SHADOW_OFFSET
object.layer.shadowRadius = COLOR_SHADOW_RADIUS
}
Fixed my own problem. The background was the same color as the text, but with a lower opacity. Xcode thinks that it should draw around text then. After using the pipet on the same color, it did made the shadow behind the label and view

adding NSImageView to NSScrollView

I have an image with a dimension of about 200x2000 pixels. I want to display the image centered in a 200x200 rectangle but I want to be able to move it up and down. Best I can figure I need to add an NSImageView to an NSScrollView but I can't figure out how or even if this is the best way. This is my first day of OS X development...
After some googling I found this from which I was able to come up with this
class MasterViewController: NSViewController {
var Photo: NSImageView!
#IBOutlet var scroll: NSScrollView!
override func viewDidLoad() {
super.viewDidLoad()
var imageRect: NSRect
self.Photo = NSImageView.init()
self.Photo.image = NSImage.init(named:"horizon")
imageRect = NSMakeRect(0.0, 0.0, self.Photo.image!.size.width, self.Photo.image!.size.height)
print("image size", imageRect)
self.Photo = NSImageView(frame: imageRect)
self.Photo.setBoundsSize(NSSize(width: imageRect.width, height: imageRect.height))
self.Photo.imageScaling = NSImageScaling.ScaleNone
self.scroll.setFrameSize(NSSize(width: imageRect.width,height: imageRect.width))
self.scroll.hasVerticalScroller = true
self.scroll.hasHorizontalScroller = true
self.Photo.setFrameSize(CGSize(width: imageRect.width,height: imageRect.width))
self.scroll.documentView = self.Photo
//print(self.scroll.documentView?.frame)
//self.scroll.setC contentSize = NSSize(width: 200, height: 2000)
//self.Photo.image = NSImage.init(named:"bezel")
//self.scroll.addSubview(self.Photo)
}
but I can't get the image to show up inside the scrollview
#lusher00: in your example, you initialize twice self.Photo, first with an init() and then with (frame: imageRect), this probably explains why image don't show up.
You could set the imageView as the documentView of the NSScrollView, as below:
#IBOutlet var scrollView: NSScrollView!
var imageRect: NSRect
// Initialize below the imageView image with appropriate content (to adapt)
imageView.image = NSImage.init(named:"horizon")
imageRect = NSMakeRect(0.0, 0.0, imageView.image!.size.width, imageView.image!.size.height)
imageView.setFrameSize(CGSize(width: imageRect.width, height: imageRect.height))
imageView.imageScaling = NSImageScaling.ScaleNone
scrollView.documentView = imageView
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = true
Just add the image view as a subview of the scrollview.
scrollView.addSubview(imageView)
You can set the position of the imageview, which will position it inside the scrollview.
The scrollview needs to know how large its content size is to enable scrolling of that area. So dont forget to update the contentSize property of the scrollview.
E.g. adding the imageView of 200x200 to the scrollView with a frame of 200x200. Setting the contentSize to 400x400 and calling imageView.center = scrollView.center, will center the image and allow some scrolling around the image, within the 200x200 visible frame of the scrollview.
You can also get the current offset of the scrollView by checking contentOffset.
If you need to track as the user scrolls, you can use scrollViewDidScroll. Check the docs for the scrollview for some other options.

UIScrollView in tvOS

I have a view hierarchy similar to the one in the image below (blue is the visible part of the scene):
So I have a UIScrollView with a lot of elements, out of which I am only showing the two button since they are relevant to the question. The first button is visible when the app is run, whereas the other one is positioned outside of the initially visible area. The first button is also the preferredFocusedView.
Now I am changing focus between the two buttons using a UIFocusGuide, and this works (checked it in didUpdateFocusInContext:). However, my scroll view does not scroll down when Button2 gets focused.
The scroll view is pinned to superview and I give it an appropriate content size in viewDidLoad of my view controller.
Any ideas how to get the scroll view to scroll?
Take a look at UIScrollView.panGestureRecognizer.allowedTouchTypes. It is an array of NSNumber with values based on UITouchType or UITouch.TouchType (depending on language version). By default allowedTouchTypes contains 2 values - direct and stylus. It means that your UIScrollView instance will not response to signals from remote control. Add the following line to fix it:
Swift 4
self.scrollView.panGestureRecognizer.allowedTouchTypes = [NSNumber(value: UITouchType.indirect.rawValue)]
Swift 4.2 & 5
self.scrollView.panGestureRecognizer.allowedTouchTypes = [NSNumber(value: UITouch.TouchType.indirect.rawValue)]
Also, don't forget to set a correct contentSize for UIScrollView:
self.scrollView.contentSize = CGSize(width: 1920.0, height: 2000.0)
Finally I solved this by setting scrollView.contentSize to the appropriate size in viewDidLoad.
You need to add pan gesture recognizer. I learned from here: http://www.theappguruz.com/blog/gesture-recognizer-using-swift. I added more code to make it not scrolling strangely, e.g. in horizontal direction.
var currentY : CGFloat = 0 //this saves current Y position
func initializeGestureRecognizer()
{
//For PanGesture Recoginzation
let panGesture: UIPanGestureRecognizer = UIPanGestureRecognizer(target: self, action: Selector("recognizePanGesture:"))
self.scrollView.addGestureRecognizer(panGesture)
}
func recognizePanGesture(sender: UIPanGestureRecognizer)
{
let translate = sender.translationInView(self.view)
var newY = sender.view!.center.y + translate.y
if(newY >= self.view.frame.height - 20) {
newY = sender.view!.center.y //make it not scrolling downwards at the very beginning
}
else if( newY <= 0){
newY = currentY //make it scrolling not too much upwards
}
sender.view!.center = CGPoint(x:sender.view!.center.x,
y:newY)
currentY = newY
sender.setTranslation(CGPointZero, inView: self.view)
}

Borders not covering background

I've got a UILabel is using a border the same color as a background which it is half obscuring, to create a nice visual effect. However the problem is that there is still a tiny, yet noticeable, sliver of the label's background color on the OUTSIDE of the border.
The border is not covering the whole label!
Changing the border width doesn't change anything either, sadly.
Here's a picture of what's going on, enlarged so you can see it:
And my code follows:
iconLbl.frame = CGRectMake(theWidth/2-20, bottomView.frame.minY-20, 40, 40)
iconLbl.font = UIFont.fontAwesomeOfSize(23)
iconLbl.text = String.fontAwesomeIconWithName(.Info)
iconLbl.layer.masksToBounds = true
iconLbl.layer.cornerRadius = iconLbl.frame.size.width/2
iconLbl.layer.borderWidth = 5
iconLbl.layer.borderColor = topBackgroundColor.CGColor
iconLbl.backgroundColor = UIColor.cyanColor()
iconLbl.textColor = UIColor.whiteColor()
Is there something I'm missing?
Or am I going to have to figure out another to achieve this effect?
Thanks!
EDIT:
List of things I've tried so far!
Changing layer.borderWidth
Fussing around with clipsToBounds/MasksToBounds
Playing around the the layer.frame
Playing around with an integral frame
EDIT 2:
No fix was found! I used a workaround by extending this method on to my UIViewController
func makeFakeBorder(inputView:UIView,width:CGFloat,color:UIColor) -> UIView {
let fakeBorder = UIView()
fakeBorder.frame = CGRectMake(inputView.frame.origin.x-width, inputView.frame.origin.y-width, inputView.frame.size.width+width*2, inputView.frame.size.height+width*2)
fakeBorder.backgroundColor = color
fakeBorder.clipsToBounds = true
fakeBorder.layer.cornerRadius = fakeBorder.frame.size.width/2
fakeBorder.addSubview(inputView)
inputView.center = CGPointMake(fakeBorder.frame.size.width/2, fakeBorder.frame.size.height/2)
return fakeBorder
}
I believe this is the way a border is drawn to a layer in iOS. In the document it says:
When this value is greater than 0.0, the layer draws a border using the current borderColor value. The border is drawn inset from the receiver’s bounds by the value specified in this property. It is composited above the receiver’s contents and sublayers and includes the effects of the cornerRadius property.
One way to fix this is to apply a mask to a view's layer, but I found out that even if so we still can see a teeny tiny line around the view when doing snapshot tests. So to fix it more, I put this code to layoutSubviews
class MyView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
let maskInset: CGFloat = 1
// Extends the layer's frame.
layer.frame = layer.frame.inset(dx: -maskInset, dy: -maskInset)
// Increase the border width
layer.borderWidth = layer.borderWidth + maskInset
layer.cornerRadius = bounds.height / 2
layer.maskToBounds = true
// Create a circle shape layer with true bounds.
let mask = CAShapeLayer()
mask.path = UIBezierPath(ovalIn: bounds.inset(dx: maskInset, dy: maskInset)).cgPath
layer.mask = mask
}
}
CALayer's mask