How add background image to UIControl - ios

I create 3rd party keyboard and i try add background to my keys. I use UIControl for my keys, without storyboard.
I have several types of buttons and try to add background UIView for my characters.
let img = UIImage(named:"KeyBackground")
var bgImage: UIImageView?
bgImage = UIImageView(image: img)
bgImage!.frame = keyboardKey.frame
keyboardKey.addSubview(bgImage!)
keyboardKey.sendSubviewToBack(bgImage!)
keyboardKey.backgroundColor = UIColor.clearColor()
But is don't work.
I try to add background image like this:
keyboardKey.backgroundColor = UIColor(patternImage: UIImage(named:"KeyBackground")!)
But is looks bad...
What am i doing wrong?

The background looks like that because the size of your image is a little smaller than the size of each key, and the image is being tiled (repeated to fill the space - so each key contains the background image and pieces of the surrounding tiles to the right, bottom, and bottom-right).
The UIColor(patternImage:) docs say that
During drawing, the image in the pattern color is tiled as necessary to cover the given area.
Your first solution probably didn't work because you inserted your UIImageView as the bottom-most subview - I assume another (opaque) view was on top of it. What type of UIControl are you using? UIButton, for example, already provides some "background image" support out of the box.

Oh, it's so easy. My keyboardKey.frame, at the time of the call this method, have frame = 0, 0, 0, 0.
Night a bad time for work:)

Related

Keep aspect ratio for UIbuttons background image

I've been looking for hours and all I find is old answers saying that it cannot be done.
I have a button where I'd like the background image to be as large as it can be, while keeping its aspect ratio. The background image keeps getting streched no matter what I do. I've tried.
var bluecircle = #imageLiteral(resourceName: "BLUE.png")
monBreak.contentMode = UIViewContentMode.scaleAspectFit
monBreak.setBackgroundImage(bluecircle, for: UIControlState.normal)
Do I really need to make an imageview and put an invisible button over it? That seems like welcoming A LOT of new things that could go wrong.
I tried
#IBOutlet weak var monBreak: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
var bluecircle = #imageLiteral(resourceName: "BLUE.png")
let theimagebehindmonBreak = UIImageView(image: bluecircle)
theimagebehindmonBreak.frame = CGRectFromString( "{{0,0},{40,40}}")
monBreak.contentMode = UIViewContentMode.scaleAspectFit
monBreak.addSubview(theimagebehindmonBreak)
theimagebehindmonBreak.image=bluecircle
theimagebehindmonBreak.contentMode = UIViewContentMode.scaleAspectFit
This gets the aspect ratio right, but since I want the layout to be dynamic setting its size to fixed values won't work, plus it's not centered.
At first I tired simply applying the constraints of the button like so
var dacontraints = NSLayoutConstraint(monBreak.constraints)
But at this point I get the error "Cannot invoke initializer for type 'NSLayoutConstraint' with an argument list of type '{[NSLayoutconstraints]}'
This is killing me
Sounds like a solution where subclassing fits.
Subclass UIButton, add an ImageView in the init, size it to the frame, and set the contentMode properly.
Old question but since I was looking for the same I think this is still valid.
I was trying to do the same (as everyone says) for backgroundImage it is impossible. However, if your button will consist of only an icon, then first you should be using the setImage method AND if you are using it you'll have access to the imageView property of the button. Since this is an UIImageView you can set the contentMode to whatever you like.

UISegmentedControl maintain aspect ratio on image

I'm having a hard time making images on a UISegmentedControl keep their aspect ratio and not scale to all sides.
Here's what it looks like:
The images are 100X100(except nr 6 gonna replace soon) and I want them to maintain the aspect ratio.
I have tried:
self.segment.contentMode = .ScaleAspectFit
//and:
self.segment.contentMode = UIViewContentMode.Center
Are there a way I can target the UIImageView in the segment..that way I can set the contentMode..right? Or is there another approach?
Thanks
segmentedControl.subviews.flatMap{$0.subviews}.forEach { subview in
if let imageView = subview as? UIImageView, let image = imageView.image, image.size.width > 5 {
// The imageView which isn't separator
imageView.contentMode = .scaleAspectFit
}
}
Actually, there's a great, general purpose solution for this:
UIImageView.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).contentMode = .scaleAspectFit
This uses the approach described here: UIImageView.appearance is overriding UISegmentedControl.appearance
In my case, I constrained it to a subclass of UISegmentedControl (in case I want the default aspectFill for other situations).
I didn't find how to set the contentMode to ScaleAspectFit but you can use the following code to set a margin around your image when you are setting the image :
yourSegmentedControl.setImage(yourImage.resizableImage(withCapInsets: .init(top: 0, left: 10, bottom: 0, right: 10), resizingMode: .stretch), forSegmentAt: 0)
You can change the values of "top", "left", "bottom" and "right" as you want.
This worked for me, I hope it will help!
It is probably late for this, but Im sure it will help someone.
My Problem #1:
Images in the segmented control are distorted in ratio.
My Problem #2:
You can't even change the colour of the image. It remains black. Even if you use .alwaysTemplate and imageview tint colour. It wont budge.
Solution:
Forget trying to hack the SDK, or achieving the goal through unofficial means. Apple can easily change the SegmentedControl and all your work becomes redundant.
Use this instead: BetterSegmentedControl. Happy coding.
It is highly customisable and easy to use, plus it supports images.

How to programmatically create a UISlider like that of Apple Music in Swift

I'm looking to create a UISlider like the one below:
I've seen code like the following to change the image, but ideally I'd like to forgo using an image and create a basic downward line programmatically.
var thumbImage : UIImage = UIImage(named: "yourImage")!
var size = CGSizeMake( thumbImage.size.width * ratio, thumbImage.size.height * ratio )
self.setThumbImage( self.imageWithImage(thumbImage, scaledToSize: size), forState: UIControlState.Normal )
A UISlider is designed to use an image for the "thumb" control. If you want to draw the thumb control programmatically you will need to create your own control. A slider isn't that complicated. It would be fairly straightforward. (But it would be a heck of a lot easier to just use the standard slider control with a red line as the thumb image.)

CALayer within UIButton

I am building a menu based upon buttons. I am building them purely in code.
let menu00 = UIButton()
menu00.frame=menuHome
let imageSubLayer = CALayer()
imageSubLayer.contents = UIImage(named: "menuIcon.png")!.CGImage
menu00.layer.insertSublayer(drawHexFill(menu00.frame, fillColor: UIColor.lightGrayColor()), atIndex: 2)
menu00.layer.insertSublayer(drawHexBorder(menu00.frame, fillColor: UIColor.clearColor()), atIndex: 1)
menu00.layer.insertSublayer(imageSubLayer, atIndex: 0)
menu00.titleLabel!.text="MENU"
menu00.titleLabel!.textColor=UIColor.whiteColor()
menu00.tag=100
self.view.addSubview(menu00)
drawHexFill and drawHexBorder are two UIBezierPath methods to draw the graphical layers, which I do as the button may have different colour border and fill depending on the situation.
The problem I have is that the text and the image are not visible. If I add the image as the button image, it is visible, however behind the hex border and hex fill layers.
I have tried different positions "atIndex" for all objects but simply cannot get what I want. I would like hexFill in the background, hexBorder next and image or text on top.
Any suggestions?
The problem is possibly that your subLayers have different values of their .zPosition property. From
Adds a new sublayer object to the current layer. The sublayer is added
to the end of the layer’s list of sublayers. This causes the sublayer
to appear on top of any siblings with the same value in their
zPosition property.
From here. You could double-check that the .zPosition property has the same value for all your three sublayers.
If this is not the issue, try using insertSubLayer:above instead of insertSubLayer:atIndex (see documentation).

IOS:UITabbar item click again and again it is reducing the UITabbar button item size in IOS 7

I'm took the Tabbar viewcontroller in this ,I added the 5 item and .I given the image insects is (24,0,0,6).
All button images are added in xib [under the Bar item -->image]Please help.
Thanks.
Adding to a similar answer here:
iOS Tab Bar icons keep getting larger
Not sure if this is an iOS7 bug but I've noticed that image insets need to be balanced.
You have specified insets for top and right but:
if you set a top inset, in order to balance it, you need to set the negative of it to the bottom inset
if you set a right inset, in order to balance it, you need to set the negative of it to the left inset
So, instead of having image insets like (24,0,0,6), use balanced image insets such as UIEdgeInsetsMake(24,-6,-24,6)
Doing so should protect your tabBarItem image from getting whacked on every tap.
If this doesn't suit your requirements, then redesign your tabBarItem image so you can have balance insets or... no insets at all.
Here's the workaround for a bug I've encountered with UITabBarController's UITabBar. If I tap a UITabBarItem once after it's selected, the icon shrinks. What I'd like to do is disable touches. UITabBarItem only has a setting for isEnabled, which grays it out if I set it to false...not what I was looking for.
I used a derivative of this answer to figure it out. With a UITabBarController with 3 tabs, printing tabBarController.subviews, I saw 3 UITabBarButtons and a UIBarBackground. The origin of UIBarBackground's frame was always (0, 0), putting it at the front of the sorted array, so I really don't need to know what the subview is, just "where it is" and whether it will always be there. The UIBarBackground is always going to be at the front of an array of tabBarController.subviews sorted by frame.minX, so I just need to remove it from the front.
Solution
Here's what the extension looks like:
extension UITabBarController {
var buttonViews: [UIView] {
var tabBarButtons = tabBar.subviews.sorted(by: {$0.frame.minX < $1.frame.minX})
tabBarButtons.removeFirst()
return tabBarButtons
}
}
I also created a struct in my Constants file, so I don't have to remember tab names:
struct TabBarItem {
static let firstTab = 0
static let secondTab = 1
static let thirdTab = 2
}
...and finally, where to use it:
In viewDidAppear (NOT viewDidLoad), add the following line to disable the UITabBarItem that you don't want to disable, but not gray out:
tabBarController?.buttonViews[TabBarItem.firstTab].isUserInteractionEnabled = false
In viewWillDisappear, re-enable the tab, as follows:
tabBarController?.buttonViews[TabBarItem.firstTab].isUserInteractionEnabled = true

Resources