How to access Image Assets like an array in Swift - swift

In my app I'm allowing the user the change some of the UI elements based on color. So, I have three versions of an image which can be used for a button and I'd like to select the image programmatically:
PSEUDO CODE
"image0", "image1", "image3"
var userChoice:integer
myButton.setImage("myImage"+userChoice , .normal)
I've seen this solution in SO:
Programmatically access image assets
What would be the Swift equivalent code?
Right now I'm using image literal:
self.But_Settings.setImage(#imageLiteral(resourceName: "settingswhite"), for: UIControlState.normal)
but of course Xcode changes this part "#imageLiteral(resourceName: "settingswhite")" to an icon which cannot be edited.

Then don't use image literal. Image literals are just that - a hard value in code that you can't change during run time. Load an image dynamically from your bundle:
if let image = UIImage(named: "myImage" + userChoice) {
self.But_Settings.setImage(image, for: .normal)
}

Do you think this would help? : But_Settings.setImage(UIImage(named: "play.png"), for: UIControlState.normal). Here you are using name of the asset

Since it's a limited number of choices it sounds like a good place for an enum.
enum ImageChoice: Int {
case zero = 0, one, two
var image: UIImage {
switch self {
case .zero:
return // Some Image, can use the icon image xcode provides now
case .one:
return //another image
case .two:
return //another image
}
}
}
Then you can easily get the correct image by initializing the enum by using an Int value.
guard let userChoice = ImageChoice(rawValue: someInt) else { return //Default Image }
let image = userChoice.image

Related

Swift macOS wallpaper set fit style

I managed to set the wallpaper for macOS by:
let workspace = NSWorkspace.shared
if let screen = NSScreen.main {
try workspace.setDesktopImageURL(imgurl, for: screen, options: [:])
//imgurl is the url location of the required image
}
} catch {
print(error)
}
However, how do I set the fit style (like fill screen, fit to screen, etc)? Will it be in options?
This solved it :
try workspace.setDesktopImageURL(imgurl, for: screen, options: [NSWorkspace.DesktopImageOptionKey.imageScaling : 5])
//The value of the dictionary is the desired number you want to scale the image by.

How can I iterate through an array of imageUrls on Firestore, to then return as images based on their index in UIPickerView?

Currently, I am fetching imageUrls from Firestore using my 'tuwos' delegate (code not included). I then use a forIn loop, where I use a print statement to make sure each individual imageUrl has been fetched successfully (they are). Also in my forIn loop, I use the Kingfisher cocoapod to set an imageView's image based on each imageUrl. Finally, I return imageView.image, but the default image, "girl_0", is being shown each time, meaning images are not being displayed from Firestore.
func pickerView(_ pickerView: AKPickerView, imageForItem item: Int) -> UIImage {
let tuwos = self.delegate?.tuwos
let imageView = UIImageView(image: #imageLiteral(resourceName: "jane2"))
if item == 0 {
for (index, element) in tuwos!.enumerated() {
if index == 0 {
let imageName = "\(element.profileImageUrl)"
print("element image url:", element.profileImageUrl)
let url = URL(string: imageName)
imageView.kf.setImage(with: url)
}
}
}
imageView.image = UIImage(named: "girl_0")!.imageWithSize(CGSize(width: 82, height: 82))
return imageView.image!
}
Other info:
(1) I'm using the AKPickerView cocoapod for a Horizontal Picker View, but the logic seems the same ('item' refers to their index).
(2) The 'tuwos' delegate is referring to where I query Firestore.
(3) I only set the code to execute for 'if item == 0' to see if it would execute at all, then was planning to figure out an abstraction to execute for each item in my pickerView. I suspect my problem is to do with my forIn loop, and that nothing is executing outside of it, hence returning the default for item 0.
This is my first post so apologies if I've missed anything, but happy to provide any info you need. I have looked around quite a lot trying to get the answer on my own (URLSession/kingfisher/sdwebimage/escaping closure/forin loop articles) but struggling on this one.

How to make `attributedReadMoreText` in `ReadMoreTextView` library not selectable - swift

I am a new iOS programming. Now i am creating a sample app which display text using ReadMoreTextView library. My content may contain many lines but by using this library i can maximumNumberOfLines to display how many lines of content should be displayed. I implement those content in cell of UITableView and i have problem is that, when i use label.attributedReadMoreText = NSAttributedString(string: "...") then end of content will display ... and when i click on it and then whole content will be display so, my question is that: How to not letting user click on that ... because i want user to click on cell then i will show another view and display whole content there?
How can i achieve something like this? Thank in advance.
This is how i set UITextView
lazy var categoryShortDetailLabel: ReadMoreTextView = {
let label = ReadMoreTextView()
label.font = UIFont(name: "SFCompactText-Regular", size: 16)
label.textColor = .black
label.isEditable = false
label.isSelectable = false
label.maximumNumberOfLines = 3
label.shouldTrim = true
label.attributedReadMoreText = NSAttributedString(string: "...")
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
Looking at the code here, I found that, the ReadMoreTextView is meant to provide you the feature like, ReadMore and ReadLess for the larger texts in textView.
However your requirement is to stop that functionality. Now, if you take a look at the code here, you will get the idea, that the function shoreMoreText and it's a private function so, can't override it. and this function is expanding the texts and setting the numberOfLines to zero. so, what you can do is, comment the code within and return from function to stop doing the action. Also as the ReadMoreTextView is Licensed as MIT(Read licence here) so, it's okay to modify the code.
private func showMoreText() {
return
/*if let readLessText = readLessText, text.hasSuffix(readLessText) { return }
shouldTrim = false
textContainer.maximumNumberOfLines = 0
if let originalAttributedText = _originalAttributedText?.mutableCopy() as? NSMutableAttributedString {
attributedText = _originalAttributedText
let range = NSRange(location: 0, length: text.count)
if let attributedReadLessText = attributedReadLessText {
originalAttributedText.append(attributedReadLessText)
}
textStorage.replaceCharacters(in: range, with: originalAttributedText)
}
invalidateIntrinsicContentSize()
invokeOnSizeChangeIfNeeded()*/
}
Try and share your results.
Hope it helps!

How can I UITest the change of the image of a UIButton in Swift?

When I tap a UIButton, the image should change to reflect its new state (e.g. Record -> Pause etc).
In my XCode UITest function, how do I interrogate the buttons current image after the tap to assert that its image has changed correctly to the correct image's .png file?
I did it like this
// Find the button by the image name
// In this example the image's names are "record_image" and "pause_image"
// "_" are replaced by " " in the image name when searching
let recordButton = XCUIApplication().buttons["record image"]
recordButton.tap()
XCTAssertFalse(recordButton.exists) // Record button won't exist anymore since the image has changed
let pauseButton = XCUIApplication().buttons["pause image"]
XCTAssertTrue(pauseButton.exists)
pauseButton.tap()
XCTAssertFalse(pauseButton.exists)
XCTAssertTrue(recordButton.exists)
I did like this, not best way but efficient for me,
every image change I changed accessibility identifier then checked the access.ids
public func setFollowed(_ isFollowed: Bool) {
if isFollowed {
followButton.setImage(UIImage(named: "followed-green-icon"), for: .normal)
followButton.accessibilityIdentifier = "ProfileInfoView_followButton_followed"
}
else {
followButton.setImage(UIImage(named: "follow-blue-icon"), for: .normal)
followButton.accessibilityIdentifier = "ProfileInfoView_followButton_follow"
}
}
sample UI test part:
func getFollowButton(isFollowed: Bool) -> XCUIElement {
if isFollowed == true {
return app.descendants(matching: .button)["ProfileInfoView_followButton_followed"]
} else {
return app.descendants(matching: .button)["ProfileInfoView_followButton_follow"]
}
}
then tested returned element, state changed etc.

how to change image of one button by pressing other buttons?

On a viewcontroller I have 101 buttons. If one of the first 100 buttons is pressed, I want to change the image of button number 101 ( I have 100 images in this project; image1,image2,image3 etc.)
So I have done this by giving every button a tag from 0-100 and then make a switch statement based on sender.tag
#IBOutlet weak var button101 : UIButton!
var i = 1
// I hooked up all the other 100 buttons to a single IBAction
#IBAction func buttonTapped(sender: UIButton) {
switch sender.tag {
case 0: i = 1
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case 1: i = 2
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case 2: i = 3
let image = UIImage (named: "image\(i)")
button101.setImage(image, forState:.Normal)
case ..: // etc. until case 99 (because button 100 has tag 99)
default: break
This super ugly code works: It changes the image of button number 101 into the specified image(i). But I want a more elegant and better solution.
I have 2 questions:
How to initialise the 'image' constant/variable in a better way (outside the IBAction)?
What kind of (loop)statement to use instead of this large switch statement?
So: I want to determine which button is pressed, then update the value of var i, loop through the images and find and update the image of button101 with the image(i).
I hope my questions are clear. Please let me know if they are not.
Help is much appreciated!
Your switch statement acts the same as:
if sender.tag < 100 {
let image = UIImage (named: "image\(sender.tag + 1)")
button101.setImage(image, forState:.Normal)
}
You can put your UIImage at the top of your ViewController with var UIImage: UIImage! if you want to, but I do not see any reason to do this.