I am trying to program an app to change screens when it enters the range of a beacon and have been following this tutorial: https://www.hackingwithswift.com/example-code/location/how-to-detect-ibeacons
The tutorial uses the code:
func updateDistance(_ distance: CLProximity) {
UIView.animate(withDuration: 0.8) {
switch distance {
case .unknown:
self.view.backgroundColor = UIColor.gray
case .far:
self.view.backgroundColor = UIColor.blue
case .near:
self.view.backgroundColor = UIColor.orange
case .immediate:
self.view.backgroundColor = UIColor.red
to tell the app to change to different colours depending on how far the beacon is in relation to the device. I would like my app to do the same thing however instead of displaying colours I would like it to display images.
I have tried using the UIImageView but it does not provide me with the option to select an image similar to how it lets me select a colour when using UIColor
Can someone explain to me how to make it display images instead of colours?
I am using Xcode 8.3.2
Ok, you need to take several steps:
Go into interface Builder and create an image view. Set up layout constraints to place it where you want on the screen, and constraints to set its height and width to the height and width of the images you want to display.
Now open an assistant editor window and set it to "automatic", which should cause it to display the source for your view controller.
Control-drag from your image view into the top of your view controller to create an IBOutlet. Let's call it anImageView.
Create images in your app's asset catalog at the target resolutions you want to support. You probably want #2x and #3x sized images for retina devices and for the 6+. You don't need non-retina images any more since iOS 9 and later doesn't support non-retina devices any more.
Lets say you have entries in your asset catalog called "unknown.png", "far.png", "near.png" and "immediate.png" that are all the same dimensions (say 100x100 points with #2x and #3x versions, just for example.)
Now rewrite your function like this:
func updateDistance(_ distance: CLProximity) {
switch distance {
case .unknown:
anImageView.image = UIImage(named: "unknown")
case .far:
anImageView.image = UIImage(named: "far")
case .near:
anImageView.image = UIImage(named: "unknown")
case .immediate:
anImageView.image = UIImage(named: "immediate")
}
That should do it.
Related
Our application has a "dark" palette, with mostly black or charcoal backgrounds. This is creating a major problem in Apple controls that ignore (or don't even offer) control over text and background color.
UISegmentedControl is a particularly good example. It's drawn with often illegible, seemingly arbitrary text/background combinations. These controls are all set up with the exact same properties in IB, and yet you never know if they'll be legible from one view controller to the next.
Most of these are OK in "dark" mode in our app, but "light" mode is shambolic. I've spent a day experimenting with themes, UIAppearance, and setting appearance in IB and programmatically. I'm fed up with it. Does anyone actually know how to guarantee legibility in these things?
Try this,
let seg:UISegmentedControl = {
let seg = UISegmentedControl()
seg.insertSegment(withTitle: "tab 1", at: 0, animated: true)
seg.insertSegment(withTitle: "tab 2", at: 1, animated: true)
seg.selectedSegmentTintColor = .red //you can replace the colours you want
seg.backgroundColor = .lightGray //you can replace the colours you want
return seg
}()
Result
Dark Mode
Light Mode
I have recently inherited an an iOS app made in Swift 3.0 from a developer that no longer works here.
The app is made in Xcode and uses storyboards for some of the screens, but not all of them.
On a iPad in landscape orientation the main screen contains an image taking op 2/3 of the width, with a text column next to it taking up 1/3 of the screen. Below are three images each up 1/3 wide. On smaller screens all these items take up 100% of the available width and are displayed underneath each other as a long list.
This is done using the following code in MainController.swift:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews();
// On small screens, columnify the layout
let mainContent = view.viewWithTag(1) as! UIStackView; //contains large image and text
let thumbnails = view.viewWithTag(3) as! UIStackView; //three images
mainContent.axis = .horizontal
mainContent.distribution = .fillProportionally
thumbnails.axis = .horizontal
if(self.view.bounds.width < 1000) {
mainContent.axis = .vertical
mainContent.distribution = .equalSpacing
thumbnails.axis = .vertical
} else {
mainContent.axis = .horizontal
mainContent.distribution = .fillProportionally
thumbnails.axis = .horizontal
}
}
This all works well, unless the user performs the following actions:
Start in landscape orientation on iPad. Image is 2/3, text 1/3
Tap on thumbnail and navigate to a different panel.
Rotate iPad to portrait.
Navigate back to first panel.
Observe that all items are places underneath each other, the image is 100%, but text is only 1/3 of the screen, while it should be 100%
Rotate to landscape, text moves next to image.
Rotate to portrait, text now spans 100% (as it should be)
My hunch would be that manually triggering a re-layout after navigating back to the first panel would solve it, but I cannot find code related to the navigation. This seems all handled by some "Apple magic?". There is probably a way to hook into it, but without any code I don't have any pointers. My only other solution would be to try and refactor the entire application with storyboards, but before I start with that, I was hoping on getting some insights here.
I've recently tested my app in iOS 11 and for some reason I'm not able to select one of the first 12 rows in a dynamically populated table view. The didSelectRow isn't even triggered for these rows. The other rows work fine, but even when scrolling down and back up (the cells should have been re-used again by then) the first 12 rows don't work.
Even on a static table view all cells that appear on screen when switching to that view controller will not respond, neither will controls inside them, even when they are in different sections. Cells that are out of screen initially again work fine.
I'll be trying to test this in an app with boilerplate code, but is this a known bug? I couldn't find anything online about it.
I've tested this after updating the devices to iOS 11, then again from Xcode 9 beta 6 without changes to the code, and again after migrating to Swift 4. Same behaviour inside the simulator. Up to iOS 10 everything is fine, only with iOS 11 the problem occurs.
This will break my app for users in two weeks, I need to fix it, so any help or advice very much appreciated!
UPDATE: As Paulw11 suggested, there is indeed another view blocking the rows. This was notable as row 12 could only be selected in the lower part of the cell, but not in the upper part.
The cause for this issue is the following code:
extension UIViewController {
func setBackgroundImage(forTableView tableView: UITableView) {
let bgImage = UIImage(named: "Background Image.png")
let bgImageView = UIImageView(image: bgImage)
tableView.backgroundView = bgImageView
let rect = bgImageView.bounds
let effect = UIBlurEffect(style: UIBlurEffectStyle.dark)
let blurView = UIVisualEffectView(effect: effect)
let height: CGFloat
switch screenSize.height {
case 480, 568: height = 455
case 736: height = 623
default: height = 554
}
blurView.frame = CGRect(x: 0, y: 0, width: rect.width, height: height)
let container = UIView(frame: rect)
bgImageView.addSubview(blurView)
let bgOverlay = UIImage(named: "Background Overlay.png")
let bgOverlayImageView = UIImageView(image: bgOverlay)
bgOverlayImageView.alpha = 0.15
bgImageView.addSubview(bgOverlayImageView)
self.view.insertSubview(container, at: 1)
}
}
Somehow since iOS 11 this background image seems to be rendered in front of the cells. Not inserting the container view into the table view's view will solve the issue. I've tried setting the zPosition of the container's layer but it does not help. How can I move the background image behind the cells again.
It's weird that this behaviour would change from iOS 10 to 11...
UPDATE 2: Inserting the container at index -1 fixes the issue:
self.view.insertSubview(container, at: -1)
I don't get why this works, though, shouldn't this index be out of range?
UPDATE 3: As Paulw11 pointed out below, the container is completely useless, it was left over from testing and removing it fixes the issue.
The container view seems to be appearing in front of the other views and preventing touches from making it through to the table view.
As an aside, I would see if you can refactor this to use constraints; It always worries me when you see hard-coded screen sizes, as that may break when new devices are released.
I want to get a photo thumbnail for my collection view cell, this is how i did it:
imageManager.requestImageForAsset(asset as! PHAsset, targetSize:CGSizeMake(80, 80), contentMode: .AspectFit, options: nil, resultHandler: {(result, info)->Void in
cell.setThumbnail(result!)
}
})
This will get a thumbnail that is stretched, I want a square cropped thumbnail that keeps the photo's original ratio like iPhone's Photo app did.
Any ideas? Please respond in swift, because I am new to ios programming, and I start with swift, thanks.
If you are working with Interface Builder where you can set the properties on your UIImageView, take a look at these two properties:
The view mode will affect whether it looks stretched or if it fits. Sometimes, though, even though it technically fits, it may still overflow the bounds of the cell rect if your image is too big. In that case, you can enable "Clip Subviews" which will make sure the image does not display outside the bounds of the image view rect.
If you are not using Interface Builder, both of these properties can be set on the cell in code instead, i.e.:
// This is assuming your UIImageView inside your cell is
// called 'thumbnail'. You could put this code inside of your
// .setThumbnail() function instead--though it's not clear
// what all that is doing from you code snippet.
cell.thumbnail.clipsToBounds = true
cell.thumbnail.contentMode = .ScaleAspectFill
The various content modes you can choose from are defined like this in UIKit:
public enum UIViewContentMode : Int {
case ScaleToFill
case ScaleAspectFit // contents scaled to fit with fixed aspect. remainder is transparent
case ScaleAspectFill // contents scaled to fill with fixed aspect. some portion of content may be clipped.
case Redraw // redraw on bounds change (calls -setNeedsDisplay)
case Center // contents remain same size. positioned adjusted.
case Top
case Bottom
case Left
case Right
case TopLeft
case TopRight
case BottomLeft
case BottomRight
}
The goal: create a blur view in app.
The code I use:
func createBlurBackgroundView()
{
if !UIAccessibilityIsReduceTransparencyEnabled()
{
if blurredSubView == nil || blurredSubView.superview == nil
{
print("Create blurred background view")
self.backgroundColor = UIColor.clearColor()
let blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Light)
blurredSubView = UIVisualEffectView(effect: blurEffect)
blurredSubView.frame = self.bounds
self.insertSubview(blurredSubView, atIndex: 0)
}
}
else
{
print("Transparency disabled!! no blur view")
}
}
The result:
everything works fine on the simulator:
But when I ran it on the iphone and ipads, it looks like:
PLEASE NOTE I DIDN'T CHANGE THE "REDUCE TRANSPARENCY" SETTINGS!
Then when I want to take a snapshot of this black background without blur, guess what?! in the photo stream, I saw exactly the correct blur view picture...
Also, when I double clicked home button, and look at the multi-task interface, I saw the blur view effect!
More Info:
I use iphone6s, ipad air2, both iOS 9.3.1
Xcode version 7.3
I'm so tired on trying to solve this problem, I tried other methods like take snapshot image and then apply blur effect on the image, but has other bugs and other CONs
UIVisualEffectView does not work with SpriteKit. I don't know what they do differently in the back, if someone knows please feel free to edit the answer. My guess is that the underlying implementation use different APIs that don't work togheter. The simulator does all kinds of tricks to simulate the actual device so they might use something different in the back than the real devices and that's why it does work on a simulator.
Remove this line in your code
self.backgroundColor = UIColor.clearColor()