I'm trying to add an arrow or like an image to correlate to how many view I have in my UIScrollView in swift. Something in line of this
(UPDATE) - My question is how do you insert an image into your scrollview that will tell it to go forward or backwards depending on how many images you have.
Now I know there is the UIPageControl but I'm looking into an alternative way to show that there is a picture and to the right or right and left. This is the code I have so far. I'll try the best I can to explain what I'm doing.
My picSource.count is data from a website that is carrying pictures
I'm multiplying my number of views by the screenwidth
This is an if else statement that shows if a picture is there post bgImage if not post no photoprovided image.
Let me know if you need more information or if I should revise. Thanks!
// Gallery
if (picSource.count > 1){
var picNum:CGFloat = CGFloat(picSource.count)
// UI News Image Scroller
var scroll = UIScrollView(frame:CGRectMake(-5, 650, screenWidth, 260))
scroll.pagingEnabled = true
scroll.showsHorizontalScrollIndicator = false
scroll.showsVerticalScrollIndicator = false
scroll.contentSize = CGSizeMake(picNum*screenWidth, 220)
// Number of views
var numberOfViews = picSource.count
var imageName = ""
// Loop to add views to scroll view
for (var i = 0; i < numberOfViews; i++){
var myIntValue:Int = Int(screenWidth)
var xOrigin = i * myIntValue
// Creates UIImageView instance using myImage
var scrollImageView = UIImageView(frame: CGRect(origin: CGPoint(x: xOrigin, y: 5), size: CGSize(width: screenWidth, height: 250)))
// Tests which image name needs to be used
imageName = picSource[i]
// Creates image object using specified image name "...jpg"
var url = NSURL(string: "http://www/images/cl/" + adID[adCurrentTag] + "/gallery/" + imageName)
var maybeError: NSError?
if var imageData :NSData = NSData(contentsOfURL: url!,options: NSDataReadingOptions.DataReadingMappedIfSafe, error: &maybeError) {
var bgImage = UIImage(data:imageData)
scrollImageView.contentMode = .ScaleAspectFit
scrollImageView.image = bgImage
// Adds Image to scroll view
scroll.addSubview(scrollImageView)
}else if let error = maybeError {
var photoNotProvided = UIImage(named:"noPhoto800x800.png")
var photoNotProvidedView = UIImageView(frame: CGRectMake(5, 650.0, screenWidth, 300.0))
scrollImageView.image = photoNotProvided
scroll.addSubview(scrollImageView)
}
}
border.addSubview(scroll)
Related
I am creating a quiz app and having trouble changing the image which is displayed of a specific imageview that is generated in a for loop.
The following code is responsible for generating the imageviews based on the amount of questions in that specific quiz. It is called in the viewDidLoad() method:
var imageView = UIImageView()
func addProgressImages(to view: UIView, count: Int){
let screenSize = UIScreen.main.bounds.size
for i in 0..<count {
let spacing: CGFloat = 2
let tag = i + 888
let width: CGFloat = screenSize.width/CGFloat(count)
let height: CGFloat = width
if let view = view.viewWithTag(tag){
view.removeFromSuperview()
}
let x = spacing + CGFloat(i) * width
imageView = UIImageView(frame: CGRect(x: x, y: 100, width: width - spacing, height: height))
imageView.image = UIImage(named: "question_progress_empty")
imageView.tag = tag
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
//print("imageviews displaying")
}
}
I have made an attempt to change some of the images to another image when the user selects an answer to that question with an if statement:
func changeImage() {
if (optA != questionAns){
imageView.image = UIImage(named: "wrong_answer")
print("opta")
}else if(optB == questionAns){
imageView.image = UIImage(named: "wrong_answer")
print("optb")
}else if(optC == questionAns){
print("optc")
imageView.image = UIImage(named: "wrong_answer")
}else{
print("if statement not initialised")
}
}
https://imgur.com/a/zwJ4EVn - This is the output of the above code
Currently, only the last image will be changed when a user clicks a button.
I need help with modifying the imageview which is related to that specific question, e.g. if question 2 is answered, only that imageview will change while the rest remain unmodified.
Hopefully that explanation made any sense, any input would be appreciated,
Thanks.
See you are doing few things wrong.
you have taken UIImageView as instance variable as below, so after
creating all the images its holding the reference to the last
imageView.
var imageView = UIImageView()
Make the var imageView as local variable and in the func
changeImage() get the proper imageView using its tag value then
try to change its image.
If any doubt plz comment.
How to get the imageView back in changeImage() check below code.
let tag = 888 + (questionNumber - 1)
if let imageView = view.viewWithTag(tag) as? UIImageView {
// Change imageView's image here
}
You will probably want to create an array of image views:
var imageViews = [UIImageView]()
And add your UIImagesViews to that array in your loop:
for i in 0..<count {
var imageView = UIImageView()
// additional setup...
imageViews.append(imageView)
}
Then, you can later iterate over your array and change the images:
for imageView in imageViews {
imageView.image = UIImage(named: "wrong_answer")
// etc.
}
I have a UIScrollView, and am using a UIPageControl to present images. The moment the first image appears, the program crashes and indicates a nil value was found.
EDIT: I'm no longer downloading images for the Scroll View, yet I'm still getting the error. The image appears and then the program crashes. Here is the stripped down code. Totally at a loss at this point. FYI, the reason I declare the variable i is I intend to loop and add additional images:
import UIKit
class HistoryViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
var frame = CGRect(origin: CGPoint(x: 0,y :0), size: CGSize(width: 0, height: 0))
override func viewDidLoad() {
super.viewDidLoad()
self.scrollView.isPagingEnabled = true
let i = 0
frame.origin.x = self.scrollView.frame.size.width * CGFloat(i)
frame.size = self.scrollView.frame.size
let subView = UIImageView(frame: frame)
subView.image = UIImage(named: "maudite")
subView.contentMode = .scaleAspectFit
self.scrollView.addSubview(subView)
self.scrollView.contentSize = CGSize(width: self.scrollView.frame.size.width * CGFloat(1), height: self.scrollView.frame.size.height)
}
}
.....................
I have two theories why this is happening. The first is that The images for the subView that I add to the ScrollView haven't loaded yet. I'm using AlamoFireImage, which downloads images asynchronously.
This is the code that configures the Scroll View:
func configureScrollView() {
self.myScrollView.isPagingEnabled = true
for index in 0..<imageURLS.count {
frame.origin.x = self.myScrollView.frame.size.width * CGFloat(index)
frame.size = self.myScrollView.frame.size
let subView = UIImageView(frame: frame)
if let url = URL(string: imageURLS[index]) {
subView.af_setImage(withURL: (url))
subView.contentMode = .scaleAspectFit
self.myScrollView.addSubview(subView)
}
}
self.myScrollView.contentSize = CGSize(width: self.myScrollView.frame.size.width * CGFloat(imageURLS.count), height: self.myScrollView.frame.size.height)
pageControl.numberOfPages = imageURLS.count
}
The other thing that might be the cause of the issue is that I first have to download the image URL's. I do this and store them in an array. When that is complete, I call the configureScrollView(). I do the call on the Main Thread. Does the function then run on the Main Thread?
for dict in responseArray {
if let url = dict["fileName"] as? String {
let fullURL = "http://www.smarttapp.com" + url
print(fullURL)
self.imageURLS.append(fullURL)
}
}
DispatchQueue.main.async {
self.activityIndicator.stopAnimating()
self.activityIndicator.isHidden = true
self.networkingState = .finishedSearching
self.configureScrollView()
}
}
I'm trying to add a tap gesture recognizer to some UIImages that are in a side scrollview, but the images flat out won't recognize the tap and I can't see where I went wrong. I've tried "scrollView.bringSubViewToFront(imgView)" because I figured they might be getting buried in layers of other views, but that didn't do the trick either. "contentView" is the UIImageView in question, where my scrollView is just a collection of those. Any help here would be appreciated, thank you.
//function to create contentScrollView for MiniMatches
func setupMiniContentScroll(contentScroll: UIScrollView) {
let scalar:Double = 4/19
let contentViewDimension = contentScroll.frame.width * CGFloat(scalar)
let contentScrollWidth = CGFloat(LocalUser.matches.count) * (contentViewDimension + CGFloat(12)) - CGFloat(12)
let matchManager = MatchesManager()
for index in 0..<LocalUser.matches.count {
let match = LocalUser.matches[index]
matchManager.retrieveMatchThumbnail(match) { img, error in
if let img = img {
//create the mini matches views
let xOrigin = index == 0 ? 12 : CGFloat(index) * contentViewDimension + (CGFloat(12) * CGFloat(index) + CGFloat(12))
let contentFrame = CGRectMake(xOrigin, 10, contentViewDimension, contentViewDimension)
let contentView = self.makeMiniContentView(contentFrame, image: img, matchedPrice: match.matchedPrice)
let tap = UITapGestureRecognizer(target: self, action: #selector(BrowseViewController.toggleItemInfo(_:)))
contentView.addGestureRecognizer(tap)
self.miniMatchContainer.append(contentView)
//update the contentScrollView
dispatch_async(dispatch_get_main_queue()) {
let contentLabelFrame = CGRect(x: xOrigin, y: contentFrame.height + 15, width: contentFrame.width, height: 20)
let contentLabel = self.makeMiniContentLabel(contentLabelFrame, itemName: match.itemName)
let priceLabel = self.makeMiniPriceLabel(contentFrame, matchedPrice: match.matchedPrice)
contentScroll.addSubview(contentView)
contentScroll.addSubview(contentLabel)
contentScroll.addSubview(priceLabel)
contentScroll.contentSize = CGSizeMake(contentScrollWidth + CGFloat(16), contentScroll.frame.height)
}
}
}
}
}
Did you set UIImage property userInteractionEnabled to true?
I want to bind data to an array of UIImageView-es by for-loop. But I don't know how to bind as simple as Javascript data attribute.
I have an idea that making an array [UIImage : data] to do this.
Ok, here is something wrong with my code:
Questions:
How to get its patternSelector in selectDecoration?
How to create outlets binding with data in a loop? For example, How can I bind every variable pattern to each action selectDecoration() ?
func selectDecoration(recognizer: UITapGestureRecognizer) {
print("OK")
}
let patternSelectorHeight: CGFloat = 120
var i : Int = 0
//var patternViews = [UIImageView]()
for pattern in decorationPatterns {
let patternSelector = UIImageView(image: UIImage(named: "test.jpg"))
if let p = patternSelector.image {
let proportion = p.size.width / p.size.height
let w = proportion * patternSelectorHeight
let patternX: CGFloat = (w + Conf.Size.margin) * CGFloat(i) + Conf.Size.margin
let patternOrigin = CGPoint(x: patternX, y: decorationSelectionTitleHeight)
patternSelector.userInteractionEnabled = true
patternSelector.frame = CGRect(origin: patternOrigin, size: CGSize(width: w, height: patternSelectorHeight))
patternSelector.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "selectDecoration:"))
decorationBg.addSubview(patternSelector)
decorationBg.bringSubviewToFront(patternSelector)
//patternViews.append(patternSelector)
}
i++
}
There is no inbuilt support for data binding in Swift. You need to keep a reference to your UIImageView objects, probably, as you suggest, in an array, so that you can update them later.
You need to set patterSelector.userInteractionEnabled=true for the UITapGestureRecognizer to work.
let patterSelectorSize = CGSize(width: 80.0, height: 160.0)
var imageViews = [UIImageView]() // This probably needs to be an instance variable so you can access it outside of this function
var i : Int = 0
for _ in decorationPatterns {
let patternX: CGFloat = (patterSelectorSize.width + 10) * CGFloat(i) + 10
let patternOrigin = CGPoint(x: patternX, y: CGFloat(60))
let patterSelector = UIImageView(image: UIImage(named: "default.jpeg"))
patterSelector.frame = CGRect(origin: patternOrigin, size: patterSelectorSize)
patterSelector.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "selectDecoration:"))
patterSelector.userInteractionEnabled=true
imageViews.append(patterSelector)
decorationBg.addSubview(patterSelector)
decorationBg.bringSubviewToFront(patterSelector)
i++
}
You must also ensure that userInteractionEnabled is true in decorationBg otherwise touches won't be propagated to your image views
(1) How to create outlets binding with data in a loop?
If you would like to bind String data then try accessibilityLabel property. You can set & retrieve value silently.
(2) why the UITapGestureRecoginzer in follow doesn't work at all?
You missed to enable the userInteractionEnabled of your UIImageView
Hope this helps you.
I have a viewController that loads a bunch of pictures into a scrollView. It takes a bit of time to load when you first enter so it slows down the UI. I am trying to find the best way to resolve. Maybe I should only load a certain amount of images at a time, but I thought I could just load it before it's shown in the previous view controller.
Here is the function in my viewController that takes a long time to load:
func loadImages() {
var documentPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
var files: NSArray = NSFileManager.defaultManager().contentsOfDirectoryAtPath(documentPath, error: nil)!
var currentX: CGFloat = 0.0
for image in files {
var im : NSString = image as NSString
var imagePath = documentPath.stringByAppendingPathComponent(im)
var image = UIImage(contentsOfFile: imagePath)
var imageView = UIImageView(image: image)
var rect = imageView.frame
rect.origin.x = currentX
imageView.frame = rect
// imageView.contentMode = .ScaleAspectFill
imageView.frame.size.width = UIScreen.mainScreen().bounds.width
imageView.frame.size.height = UIScreen.mainScreen().bounds.height
currentX += imageView.frame.size.width
self.scrollView.addSubview(imageView)
}
// currentX += UIScreen.mainScreen().bounds.width
self.scrollView.contentSize = CGSizeMake(currentX, self.scrollView.frame.size.height)
self.scrollView.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleLeftMargin | UIViewAutoresizing.FlexibleRightMargin
}
In my previous view controller I tried just doing:
var imageView = ImagesViewController().view
But that does not seem to do it. I get: fatal error: unexpectedly found nil while unwrapping an Optional value
Is there any way to do it? Or another solution you would recommend?
Thanks.
i think your problem not in UI. Where do you call loadImage method? (better not to load images in the main queue) For more quick work with image you can decompress them.
UIGraphicsBeginImageContextWithOptions(CGSizeMake(1, 1), NO, 0);
[image drawInRect:CGRectMake(0, 0, 1, 1)];
UIGraphicsEndImageContext();
Call your loadImages() inside init() or whatever custom initializer you're using.