Certain UIImageViews in puzzle game won't move to new CGPoint center - ios

I have 8 UIImageViews in a frame of 9 equal spaces. All of the views except two (the top row) move to the emptySpot when touched. Can't figure out why.
(As a side note, I can't figure out why the first few lines of code in my blockquote don't format/show as code like the rest!?)
import UIKit
import Foundation
var tiledViewsStack = [UIImageView]()
var emptySpot = CGPoint()
class PhotoViewController: UIViewController,
UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//Choose an image from Photo Library and display on screen in displayImageView
#IBOutlet weak var displayImageView: UIImageView!
#IBAction func choosePicFromLibrary(sender: AnyObject) {
let imagePicker: UIImagePickerController = UIImagePickerController()
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
imagePicker.delegate = self
imagePicker.modalPresentationStyle = UIModalPresentationStyle.Popover
if (imagePicker.popoverPresentationController != nil) {
imagePicker.popoverPresentationController!.sourceView = sender as! UIButton
imagePicker.popoverPresentationController!.sourceRect = (sender as! UIButton).bounds
}
presentViewController(imagePicker, animated: true, completion: nil)
}
#IBAction func takePhoto(sender: AnyObject) {
let imagePicker: UIImagePickerController = UIImagePickerController()
imagePicker.sourceType = UIImagePickerControllerSourceType.Camera
imagePicker.delegate = self
imagePicker.modalPresentationStyle = UIModalPresentationStyle.Popover
if (imagePicker.popoverPresentationController != nil) {
imagePicker.popoverPresentationController!.sourceView = sender as! UIButton
imagePicker.popoverPresentationController!.sourceRect = (sender as! UIButton).bounds
}
presentViewController(imagePicker, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
dismissViewControllerAnimated(true, completion: nil)
displayImageView.image = info[UIImagePickerControllerOriginalImage] as! UIImage!
}
func imagePickerControllerDidCancel(picker: UIImagePickerController) {
dismissViewControllerAnimated(true, completion: nil)
}
//Cut photo into 9 tiles
//Cut selected image into 9 pieces and add each cropped image to tileImageStack array
var tileImageStack = [AnyObject]()
var allCenters = [NSValue]()
#IBAction func randomize(sender: AnyObject) {
let selectedImageWidth = displayImageView.image!.size.width
let selectedImageHeight = displayImageView.image!.size.height
let tileSize = CGSizeMake(selectedImageWidth/3, selectedImageHeight/3)
for (var colI = 0; colI < 3; colI++)
{
for (var rowI = 0; rowI < 3; rowI += 1)
{
let tileRect = CGRectMake(CGFloat(rowI) * tileSize.width, tileSize.height * CGFloat(colI), tileSize.width, tileSize.height)
if let selectedImage = displayImageView.image
{
let tileImage = CGImageCreateWithImageInRect(selectedImage.CGImage, tileRect)
let aUItile = UIImage(CGImage: tileImage!)
tileImageStack.append(aUItile)
}
}
}
//Display tiles in order on screen, then mix them up randomly
let frameWidth = self.view.frame.width
let frameHeight = self.view.frame.height
var xCen = (frameWidth/3)/2
var yCen = (frameHeight/3)/2
var pieceNumber = 0
for (var v = 0; v < 3; v += 1)
{
for (var h = 0; h < 3; h += 1)
{
let tiledView = UIImageView(frame:CGRectMake(0, 0, frameWidth/3, (frameHeight)/3))
var curCenter = CGPointMake(xCen, yCen)
allCenters.append(NSValue(CGPoint: curCenter))
//tiledView.backgroundColor = UIColor.redColor()
tiledView.center = curCenter
tiledView.image = tileImageStack[pieceNumber] as? UIImage
tiledView.userInteractionEnabled = true
tiledViewsStack.append(tiledView)
self.view.addSubview(tiledView)
xCen += (frameWidth/3)
pieceNumber += 1
}
xCen = (frameWidth/3)/2
yCen += (frameHeight/3)
}
tiledViewsStack[0].removeFromSuperview()
tiledViewsStack.removeAtIndex(0)
//Now there are 8 imageViews in the tiledViewsStack array, and 9 centers stored in allCenters array.
var centersCopy = allCenters
var randLocInt = Int()
var randLoc = CGPoint()
for any in tiledViewsStack
{
randLocInt = Int(arc4random() % UInt32(centersCopy.count)) // 0, --- 8
randLoc = centersCopy[randLocInt].CGPointValue()
any.center = randLoc
centersCopy.removeAtIndex(randLocInt)
}
emptySpot = centersCopy[0].CGPointValue()
}
var tapCen = CGPoint();
var left = CGPoint();
var right = CGPoint();
var top = CGPoint();
var bottom = CGPoint();
var leftIsEmpty = false
var rightIsEmpty = false
var topIsEmpty = false
var bottomIsEmpty = false
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?)
{
let frameWidth = self.view.frame.width
let frameHeight = self.view.frame.height
let allTouches = event?.allTouches()
let myTouch = allTouches?.first
if myTouch!.view != self.view
{
tapCen = myTouch!.view!.center
left = CGPointMake(tapCen.x - (frameWidth/3), tapCen.y)
right = CGPointMake(tapCen.x + (frameWidth/3), tapCen.y)
top = CGPointMake(tapCen.x, tapCen.y - (frameHeight/3))
bottom = CGPointMake(tapCen.x, tapCen.y + (frameHeight/3))
if (emptySpot == left) {leftIsEmpty = true}
if (emptySpot == right) {rightIsEmpty = true}
if (emptySpot == top) {topIsEmpty = true}
if (emptySpot == bottom) {bottomIsEmpty = true}
if (leftIsEmpty || rightIsEmpty || topIsEmpty || bottomIsEmpty)
{
//UIView.animateWithDuration(0.5, animations: myTouch!.view!.center = emptySpot, completion: true)
UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.TransitionNone, animations: { () -> Void in
myTouch!.view!.center = emptySpot
}, completion: { (finished: Bool) -> Void in
})
emptySpot = tapCen
leftIsEmpty = false; rightIsEmpty = false; topIsEmpty = false; bottomIsEmpty = false;
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
} }

If you use auto-layout then moving a view's center or frame often doesn't work as expected because the constraints override the view's position.
(It works until something causes the layout of the views to be updated. At that point the constraints override the changes you've made.)
With auto-layout you need to add outlets to your constraint(s) and then change the constant values on those constraints in order to move your views.
As for your code, indenting by > 4 spaces is what marks a block of text as code. Your first few lines were not indented enough. (I fixed it.)
BTW. There's no reason to use block quotes on your code. Select the code, click the curly braces code button on the editor, and it indents the code the required 4 spaces.
(I was too lazy to remove all the unneeded "> " block quote prefixes on your code lines. You should probably do that.)

Related

Smiley Rating Bar swift

If we had to do this Smiley Rating Bar on iOS...how we can do?
In the link-example, use a gif, but let's avoid this
If I had to do it ... I would use 5 images of faces for the background with their respective descriptions.
For the face that moves in its position X would use UIPanGestureRecognizer:
class ViewController: UIViewController , UIGestureRecognizerDelegate , UITextFieldDelegate{
#IBOutlet weak var image1: UIImageView!
var panGesture = UIPanGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
panGesture = UIPanGestureRecognizer(target: self, action: #selector(ViewController.draggedView(_:)))
image1.isUserInteractionEnabled = true
image1.addGestureRecognizer(panGesture)
}
func draggedView(_ sender:UIPanGestureRecognizer){
self.view.bringSubview(toFront: image1)
let translation = sender.translation(in: self.view)
image1.center = CGPoint(x: image1.center.x + translation.x, y: image1.center.y)
sender.setTranslation(CGPoint.zero, in: self.view)
}
}
The question I have is how do I move the image1 to detect what is going on "above" the images below. Like this:
So...any help I will appreciate
I have done the same thing, Please use
https://github.com/gali8/G8SliderStep/tree/master/G8SliderStep Library .Please replace the Draw labels and Draw Images method with following in G8SliderStep.swift File.
#objc internal func drawLabels() {
guard let ti = tickTitles else {
return
}
if _stepTickLabels == nil {
_stepTickLabels = []
}
if let sl = _stepTickLabels {
for l in sl {
l.removeFromSuperview()
}
_stepTickLabels?.removeAll()
for index in 0..<ti.count {
let title = ti[index]
let lbl = UILabel()
lbl.font = unselectedFont
lbl.text = title
lbl.textAlignment = .center
lbl.sizeToFit()
var offset: CGFloat = 0
if index+1 < (steps%2 == 0 ? steps/2+1 : steps/2) {
offset = trackLeftOffset/2
}
else if index+1 > (steps%2 == 0 ? steps/2+1 : steps/2) {
offset = -(trackRightOffset/2)
}
if index == 0 {
offset = trackLeftOffset
}
if index == steps {
offset = -trackRightOffset
}
let x = offset + CGFloat(Double(index) * stepWidth) - (lbl.frame.size.width / 2)
var rect = lbl.frame
rect.origin.x = x
rect.origin.y = bounds.midY - (bounds.size.height / 2) - rect.size.height + 80
lbl.frame = rect
self.addSubview(lbl)
_stepTickLabels?.append(lbl)
}
}
}
#objc internal func drawImages() {
guard let ti = tickImages else {
return
}
if _stepTickImages == nil {
_stepTickImages = []
}
if let sl = _stepTickImages {
for l in sl {
l.removeFromSuperview()
}
_stepTickImages?.removeAll()
for index in 0..<ti.count {
let img = ti[index]
let imv = UIImageView(image: img)
imv.contentMode = .scaleAspectFit
imv.sizeToFit()
var offset: CGFloat = 0
if index+1 < (steps%2 == 0 ? steps/2+1 : steps/2) {
offset = trackLeftOffset/2
}
else if index+1 > (steps%2 == 0 ? steps/2+1 : steps/2) {
offset = -(trackLeftOffset/2)
}
if index == 0 {
offset = trackLeftOffset
}
if index == steps {
offset = -trackRightOffset
}
let x = offset + CGFloat(Double(index) * stepWidth) - (imv.frame.size.width / 2)
var rect = imv.frame
rect.origin.x = x
rect.origin.y = bounds.midY - (bounds.size.height / 2)
imv.frame = rect
self.insertSubview(imv, at: 2) //index 2 => draw images below the thumb/above the line
_stepTickImages?.append(imv)
}
}
}
Please get selected and unselected emoticons image from your personal resource, and pass those image in array as done in given example.In your view controller in viewDidLoad please write this code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
sliderStepBar.stepImages = [UIImage(named:"terrible")!, UIImage(named:"bad")!, UIImage(named:"okay")!, UIImage(named:"good")!,UIImage(named:"great")!, ]
sliderStepBar.tickTitles = ["Terrible", "Bad", "Okay", "Good", "Great"]
sliderStepBar.tickImages = [#imageLiteral(resourceName: "unselectterrible"), #imageLiteral(resourceName: "unselectbad"), #imageLiteral(resourceName: "unselectokay"),#imageLiteral(resourceName: "unselectgood"),#imageLiteral(resourceName: "unselectgreat")]
sliderStepBar.minimumValue = 4
sliderStepBar.maximumValue = Float(sliderStepBar.stepImages!.count) + sliderStepBar.minimumValue - 1.0
sliderStepBar.stepTickColor = UIColor.clear
sliderStepBar.stepTickWidth = 40
sliderStepBar.stepTickHeight = 40
sliderStepBar.trackHeight = 5
sliderStepBar.value = 5
}
Enjoy the Smiley Rating.
Happy Coding.
I have created the same, Check the below image
Overview
Easy customization(Font, Colors, Images, Ticks, Height, Width, Rounded)
#IBInspectable
Tappable
Draggable
Swift 5.0 above
Xcode 11 above
Orientation support
Manual drag & drop the class
Find the GIT URL for code
SmileyRating

Strange UITextField in UINavigationBar constraint issues only on iOS 10 or higher

After I updated my iPhone to iOS 10 I noticed this very strange constraint issue with a UITextField in a UINavigationBar has appeared in my app iOS Tipped. I thought updating my Xcode project to swift 3 would fix it but the problem persists. For some reason this ins't an issue with iOS 9 and lower.
Please download my app Tipped... it's free and you will be able to see
the issue described below.
1: When I launch my app and tap the tab bar to the viewController with the textfield constraint issue in the navigation bar I get this
2: When I press another tab bar option (like the home page) the tap the search tab bar option (navigating back to the page with the issue) I get this
3: Also when I tap one of the segment buttons on the search page with the constraint issue. The constraint issue will reappear and the textfield will go too far to the right.
I have tried the below code to try to fix the problem but nothing seems to be working. Really stuck here any help would be like awesome.
override func viewWillAppear(_ animated: Bool) {
// searchTextField.becomeFirstResponder()
print("viewWillAppear: searchPageViewController")
navigationView.setNeedsLayout()
navigationView.updateConstraintsIfNeeded()
searchTextField.updateConstraints()
searchTextField.setNeedsLayout()
}
Below is the code from the viewcontroller that I am having trouble with.
class SearchPageViewController: UIPageViewController, UISearchBarDelegate, UISearchDisplayDelegate, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate, UITextFieldDelegate {
//%%% customizeable button attributes
let X_BUFFER:CGFloat = 0.0; //%%% the number of pixels on either side of the segment
let Y_BUFFER:CGFloat = 0.0; //%%% number of pixels on top of the segment
let HEIGHT:CGFloat = 44.0; //%%% height of the segment
//%%% customizeable selector bar attributes (the black bar under the buttons)
let BOUNCE_BUFFER:CGFloat = 10.0; //%%% adds bounce to the selection bar when you scroll
let ANIMATION_SPEED:CGFloat = 0.2; //%%% the number of seconds it takes to complete the animation
let SELECTOR_Y_BUFFER:CGFloat = 40.0; //%%% the y-value of the bar that shows what page you are on (0 is the top)
let SELECTOR_HEIGHT:CGFloat = 4.0; //%%% thickness of the selector bar
let X_OFFSET:CGFloat = 0.0; //%%% for some reason there's a little bit of a glitchy offset. I'm going to look for a better workaround in the future
var navigationView = UIView()
var containerView = UIView()
var buttonText:NSArray = []
var pageScrollView:UIScrollView!
var currentPageIndex:Int!
var selectionBar = UIView()
var buttonOneTap:Bool = false
var buttonTwoTap:Bool = false
fileprivate var _controllerEnum: ControllerEnum = ControllerEnum()
fileprivate var _dict: [UIViewController: ControllerEnum] = [:]
var editView = UIView()
// var delegate: ViewControllerDelegate? = nil
// var userList = NSMutableArray()
// var searchString = String()
// var viewControllerArray:NSMutableArray = NSMutableArray()
var blogSearchCollectionViewController:BlogSearchCollectionViewController!
// var pageViewController: UIPageViewController!
var pageTitles: NSArray!
var pageImages: NSArray!
let searchController = UISearchController(searchResultsController: nil)
#IBOutlet weak var searchBarView: UIView!
#IBOutlet weak var searchTextField: UITextField!
//Stretching the searchTextField full width of navbar
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
widenTextField()
}
func widenTextField() {
let paddingView = UIView(frame: CGRect(x: 0, y: 0, width: 8, height: 0))
self.searchTextField.leftView = paddingView
self.searchTextField.leftViewMode = .always
let paddingViewRight = UIView(frame: CGRect(x: 0, y: 0, width: 8, height: 0))
self.searchTextField.rightView = paddingViewRight
self.searchTextField.rightViewMode = .always
searchBarView.frame = CGRect(x: 16, y: 5, width: self.view.frame.width, height: 34)
// var frame:CGRect = self.searchTextField.frame
// frame.size.width = self.view.frame.width
// self.searchTextField.frame = CGRectMake(16, 5, self.view.frame.width, 33)
}
// TextFieldDelegates
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// textField.resignFirstResponder()
handleTap(editView)
if currentPageIndex == 0 {
let vc = self.viewControllerAtIndex(currentPageIndex) as BlogSearchCollectionViewController
// vc.loadUsers(textField.text.lowercaseString)
vc.searchText = textField.text!.lowercased()
vc.loadObjects()
vc.showActivityIndicator()
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: false, completion: nil)
} else if currentPageIndex == 1 {
let vc = self.viewControllerAtIndexTwo(currentPageIndex) as PhotoSearchController
vc.search(textField.text!.lowercased())
vc.showActivityIndicator()
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: false, completion: nil)
}
return true
}
// var lastTextFieldEdit:String!
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
showEditView()
if let text = textField.text {
if text.characters.count > 0 {
DispatchQueue.main.async{
textField.selectAll(nil)
}
}
}
searchTextField.textAlignment = NSTextAlignment.left
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
print(textField)
}
override func viewWillAppear(_ animated: Bool) {
// searchTextField.becomeFirstResponder()
print("viewWillAppear: searchPageViewController")
}
override func viewDidAppear(_ animated: Bool) {
}
override func viewDidLoad() {
super.viewDidLoad()
self.setupSegmentButtons()
self.setupPage()
currentPageIndex = 0
// self.navigationItem.titleView = searchTextField
}
//Mark: SearchBar stuff
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
// searchController.searchBar.showsCancelButton = true
return true
}
func searchBarShouldEndEditing(_ searchBar: UISearchBar) -> Bool {
searchController.searchBar.showsCancelButton = true
// for subView in searchController.view.subviews {
// if let dimView = subView as? UIView {
// dimView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.6)
// }
// }
return true
}
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
for subView in searchController.view.subviews {
}
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
print("hithere")
searchController.searchBar.showsCancelButton = true
// searchController.dimsBackgroundDuringPresentation = false
print("searchController.view.subviews1: - \(searchController.searchBar.subviews)")
for subView in searchController.view.subviews {
print("searchController.view.subviews2: - \(searchController.view.subviews)")
if let dimView = subView as? UIView {
dimView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.0)
}
}
// searchController.dismissViewControllerAnimated(true, completion: nil)
if currentPageIndex == 0 {
let vc = self.viewControllerAtIndex(currentPageIndex) as BlogSearchCollectionViewController
// vc.loadUsers(searchBarString.lowercaseString)
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: false, completion: nil)
} else if currentPageIndex == 1 {
let vc = self.viewControllerAtIndexTwo(currentPageIndex) as PhotoSearchController
vc.search(searchBarString.lowercased())
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController], direction: .forward, animated: false, completion: nil)
}
}
var searchBarString:String!
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
searchController.searchBar.showsCancelButton = true
let uiButton = searchController.searchBar.value(forKey: "cancelButton") as! UIButton
uiButton.setTitle("Cancel", for: UIControlState())
uiButton.setTitleColor(UIColor.black, for: UIControlState())
uiButton.titleLabel!.font = UIFont(name: "Helvetica Neue", size: 17)
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
searchBarString = searchText
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func setupSegmentButtons() {
navigationView = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: HEIGHT))
navigationView.backgroundColor = UIColor.brown
let numControllers = 2
// if buttonText == NSNotFound {
buttonText = NSArray(objects: "BLOGS", "TIPS")
// }
let buttonOne:UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width/2, height: HEIGHT))
let buttonTwo:UIButton = UIButton(frame: CGRect(x: self.view.frame.size.width/2, y: 0, width: self.view.frame.size.width/2, height: HEIGHT))
navigationView.addSubview(buttonOne)
navigationView.addSubview(buttonTwo)
buttonOne.tag = 0
buttonOne.backgroundColor = UIColor.white
buttonOne.addTarget(self, action: #selector(SearchPageViewController.tapSegmentButtonAction(_:)), for: UIControlEvents.touchUpInside)
buttonOne.setTitle(buttonText[0] as? String, for: UIControlState())
buttonOne.setTitleColor(UIColor.black, for: UIControlState())
buttonOne.titleLabel!.font = UIFont(name: "Interstate-Bold", size: 17)!
buttonTwo.tag = 1
buttonTwo.backgroundColor = UIColor.white
buttonTwo.addTarget(self, action: #selector(SearchPageViewController.tapSegmentButtonAction(_:)), for: UIControlEvents.touchUpInside)
buttonTwo.setTitle(buttonText[1] as? String, for: UIControlState())
buttonTwo.setTitleColor(UIColor.black, for: UIControlState())
buttonTwo.titleLabel!.font = UIFont(name: "Interstate-Bold", size: 17)
self.view.addSubview(navigationView)
self.setupSelector()
}
func setupSelector() {
selectionBar = UIView(frame: CGRect(x: X_BUFFER-X_OFFSET, y: SELECTOR_Y_BUFFER,width: (self.view.frame.size.width-2*X_BUFFER)/2, height: SELECTOR_HEIGHT))
selectionBar.backgroundColor = UIColor(red: 251/255, green: 73/255, blue: 90/255, alpha: 1.0)
// selectionBar.alpha = 1
navigationView.addSubview(selectionBar)
}
func setupPage() {
// self.navigationItem.titleView = searchTextField
view.backgroundColor = UIColor.white
//TextFieldStuff
searchTextField.delegate = self
searchTextField.placeholder = "Search for blogs"
searchTextField.textAlignment = NSTextAlignment.center
searchTextField.autocorrectionType = .no
//TextField is editing translucent view
editView.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.6)
editView.frame = CGRect(x: 0, /*self.navigationController!.navigationBar.frame.size.height + 20 +*/ y: HEIGHT, width: self.view.frame.size.width, height: self.view.frame.size.height - (self.navigationController!.navigationBar.frame.size.height + 20 + HEIGHT))
self.view.addSubview(editView)
editView.isHidden = true
//tapGesture
editView.isUserInteractionEnabled = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SearchPageViewController.handleTap(_:)))
editView.addGestureRecognizer(tapGesture)
let pageControl = UIPageControl()
pageControl.backgroundColor = UIColor.white
self.pageTitles = NSArray(objects: "Explore", "Today Widget")
self.pageImages = NSArray(objects: "page1", "page2")
//PageViewControllers
delegate = self
dataSource = self
let vc = self.viewControllerAtIndex(0) as BlogSearchCollectionViewController
// vc.loadUsers("")
vc.searchText = ""
vc.loadObjects()
vc.showActivityIndicator()
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController], direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: nil)
print("pageSetUp:- \(currentPageIndex)")
self.syncScrollView()
}
func handleTap(_ sender : UIView) {
// searchController.resignFirstResponder()
searchTextField.resignFirstResponder()
searchTextField.textAlignment = NSTextAlignment.center
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.editView.alpha = 0
}, completion: { (success:Bool) -> Void in
if success {
self.editView.isHidden = true
}
})
// UIView.animateWithDuration(0.5, animations: { () -> Void in
// self.editView.alpha = 0
// })
print("Tap Gesture recognized")
}
func showEditView() {
editView.alpha = 0
editView.isHidden = false
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.editView.alpha = 0.6
})
}
func viewControllerAtIndex(_ index: Int) -> BlogSearchCollectionViewController {
let vc: BlogSearchCollectionViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BlogSearchCollectionViewController") as! BlogSearchCollectionViewController
return vc
}
func viewControllerAtIndexTwo(_ index: Int) -> PhotoSearchController {
let vc: PhotoSearchController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PhotoSearchController") as! PhotoSearchController
// currentPageIndex = vc.pageIndex
return vc
}
func syncScrollView() {
let x = self.view.subviews
var view:UIView!
for view in x {
if view.isKind(of: UIScrollView.self) {
pageScrollView = view as! UIScrollView
pageScrollView.delegate = self
}
}
}
//%%% when you tap one of the buttons, it shows that page,
//but it also has to animate the other pages to make it feel like you're crossing a 2d expansion,
//so there's a loop that shows every view controller in the array up to the one you selected
//eg: if you're on page 1 and you click tab 3, then it shows you page 2 and then page 3
func tapSegmentButtonAction(_ button:UIButton) {
if buttonOneTap == false && buttonTwoTap == false {
let tempIndex:Int = self.currentPageIndex
//%%% check to see if you're going left -> right or right -> left
// println("buttonTag + tempIndex \(button.tag) \(tempIndex)")
if button.tag > tempIndex {
//%%% scroll through all the objects between the two points
buttonOneTap = true
// var i = tempIndex+1
// for i in stride(from:i, through:(button.tag), by: 1) {
for tempIndex in 0..<button.tag {
// for var i = tempIndex+1; i<=button.tag; i += 1 {
// println(i)
let vc: PhotoSearchController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PhotoSearchController") as! PhotoSearchController
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController] /*[getController(.Debts)!]viewControllerArray.objectAtIndex(i) as! [AnyObject]*/, direction: UIPageViewControllerNavigationDirection.forward, animated: true, completion: { (success:Bool) -> Void in
//%%% if the action finishes scrolling (i.e. the user doesn't stop it in the middle),
//then it updates the page that it's currently on
if success == true {
self.buttonOneTap = false
self.updateCurrentPageIndex(1)
// self.searchController.searchBar.placeholder = "Search for tips"
// let txtField = self.navigationItem.titleView as! UITextField
// txtField.placeholder = "Search for tips"
self.searchTextField.placeholder = "Search for tips"
}
})
}
//%%% this is the same thing but for going right -> left
} else if button.tag < tempIndex {
buttonTwoTap = true
// var i = tempIndex+1
// for i in stride(from:i, through:(button.tag), by: -1) {
// for var i = tempIndex-1; i >= button.tag; i -= 1 {
for tempIndex in (0...button.tag).reversed() {
// println(i)
let vc: BlogSearchCollectionViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BlogSearchCollectionViewController") as! BlogSearchCollectionViewController
// vc.loadUsers("")
vc.searchText = ""
vc.loadObjects()
vc.showActivityIndicator()
let viewControllers = NSArray(object: vc)
setViewControllers(viewControllers as? [UIViewController] /*[getController(_controllerEnum)!] viewControllerArray.objectAtIndex(i) as! [AnyObject]*/, direction: UIPageViewControllerNavigationDirection.reverse, animated: true, completion: { (success:Bool) -> Void in
if success == true {
self.buttonTwoTap = false
self.updateCurrentPageIndex(0)
// self.searchController.searchBar.placeholder = "Search for blogs"
// let txtField = self.navigationItem.titleView as! UITextField
// txtField.placeholder = "Search for blogs"
self.searchTextField.placeholder = "Search for blogs"
}
})
}
}
}
}
func updateCurrentPageIndex(_ newIndex:Int) {
self.currentPageIndex = newIndex
}
//%%% makes sure the nav bar is always aware of what page you're on
//in reference to the array of view controllers you gave
//%%% method is called when any of the pages moves.
var xFromCenter:CGFloat!
func scrollViewDidScroll(_ scrollView: UIScrollView) {
// println(self.currentPageIndex)
//It extracts the xcoordinate from the center point and instructs the selection bar to move accordingly
xFromCenter = self.view.frame.size.width-scrollView.contentOffset.x
print(xFromCenter)
// if xFromCenter > 0 && currentPageIndex == 0 {
// updateCurrentPageIndex(0)
// }
// println(self.currentPageIndex)
var a = X_BUFFER + selectionBar.frame.size.width
var b = CGFloat(currentPageIndex) - X_OFFSET
let xCoor = selectionBar.frame.size.width * CGFloat(self.currentPageIndex)
// println(xCoor)
//%%% checks to see what page you are on and adjusts the xCoor accordingly.
//i.e. if you're on the second page, it makes sure that the bar starts from the frame.origin.x of the
//second tab instead of the beginning
selectionBar.frame = CGRect(x: xCoor - xFromCenter/2, y: selectionBar.frame.origin.y, width: selectionBar.frame.size.width, height: selectionBar.frame.size.height)
}
// MARK: - Page View Controller Data Source
var vcOne:BlogSearchCollectionViewController!
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
var index:Int = currentPageIndex
if index == NSNotFound || index == 0 {
return nil
}
// println(currentPageIndex)
index -= 1
let vcOne = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "BlogSearchCollectionViewController") as! BlogSearchCollectionViewController
// currentPageIndex = vc.pageIndex
// println("actaulIndexBlogSearchCollectionViewController: - \(actaulIndex)")
return vcOne
// return getController(_dict[viewController]!.prevIndex())
}
var vcTwo:PhotoSearchController!
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
var index:Int = currentPageIndex
if index == NSNotFound {
return nil
}
index += 1
if index == buttonText.count {
return nil
}
vcTwo = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "PhotoSearchController") as! PhotoSearchController
// currentPageIndex = vc.pageIndex
// if vc.pageIndex == 1 && index == 0 {
// return vc
// }
// println("actaulIndexPhotoSearchController: - \(actaulIndex)")
return vcTwo
// return getController(_dict[viewController]!.nextIndex())
}
var actaulIndex:Int!
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
print("finished: - \(finished)")
print("completed: - \(completed)")
if finished == true && completed == true {
print("currentPageIndex: - \(currentPageIndex)")
if finished == true && completed == true && currentPageIndex == 0 && xFromCenter < 0 {
print("hi")
// searchController.searchBar.placeholder = "Search for tips"
// let txtField = self.navigationItem.titleView as! UITextField
// txtField.placeholder = "Search for tips"
searchTextField.placeholder = "Search for tips"
updateCurrentPageIndex(1)
} else if finished == true && completed == true && currentPageIndex == 1 && xFromCenter > 0 {
print("hi 2")
// searchController.searchBar.placeholder = "Search for blogs"
// let txtField = self.navigationItem.titleView as! UITextField
// txtField.placeholder = "Search for blogs"
searchTextField.placeholder = "Search for blogs"
updateCurrentPageIndex(0)
}
}
}
}
I figured it out. Inside the widen textfield function. I needed to change the following line:
searchBarView.frame = CGRect(x: 16, y: 5, width: self.view.frame.width, height: 34)
to
searchBarView.frame = CGRect(x: 8, y: 5, width: self.view.frame.width - 16, height: 34)

How to apply an animation effect to UIImageView slideshow

On Swift 3.0 how can I apply some animation effect to this slideshow? Cannot find animation effects related to animationWithDuration method.
let image1 = UIImage(named: "image1")!
let image2 = UIImage(named: "image2")!
let image3 = UIImage(named: "image3")!
var imagesArray : [UIImage] = []
override func viewDidLoad() {
super.viewDidLoad()
imagesArray = [image1, image2, image3]
myView.clipsToBounds = true
myView.animationImages = imagesArray
myView.animationDuration = 10.0
myView.animationRepeatCount = 0
myView.startAnimating()
}
It looks like you are using the build in frame animation for UIImageView. This is designed to just cycle through the images, like an animated gif. It doesn't really have more sophisticated animation than that. What you can do if you want transition effects is alternate between two image views and use the UIView Animation methods to switch between them. This just does a crossfade by manipulating alpha:
var images = [UIImage]()
var currentImageindex = 0
func animateImageViews() {
swap(&firstImageView, &secondImageView)
secondImageView.image = images[currentImageindex]
currentImageindex = (currentImageindex + 1) % images.count
UIView.animate(withDuration: 1, animations: {
self.firstImageView.alpha = 0
self.secondImageView.alpha = 1
}, completion: { _ in
self.animateImageViews()
})
}
Here is playground that shows how it works. You need to drop 2 images into the resources folder named 1.png and 2.png for it to work. Note that setting the view frames like this is horrible programming practice i just did it here for brevity. use interface builder and autolayout in your actual code.
import PlaygroundSupport
import UIKit
class Demo: UIViewController {
let button = UIButton()
var firstImageView = UIImageView()
var secondImageView = UIImageView()
var images = [UIImage]()
var currentImageindex = 0
override func viewDidLoad() {
view.addSubview(firstImageView)
view.addSubview(secondImageView)
images.append(UIImage(named: "1.png")!)
images.append(UIImage(named: "2.png")!)
firstImageView.image = images[0]
secondImageView.image = images[1]
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
firstImageView.frame = view.frame
secondImageView.frame = view.frame
}
override func viewDidAppear(_ animated: Bool) {
animateImageViews()
}
func animateImageViews() {
swap(&firstImageView, &secondImageView)
secondImageView.image = images[currentImageindex]
currentImageindex = (currentImageindex + 1) % images.count
UIView.animate(withDuration: 1, animations: {
self.firstImageView.alpha = 0
self.secondImageView.alpha = 1
}, completion: { _ in
self.animateImageViews()
})
}
}
let viewcontroller = Demo()
viewcontroller.view.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
PlaygroundPage.current.liveView = viewcontroller.view

Error: index beyond bounds

I have been getting the error of index beyond bounds.
I have been dealing with ZLSwipeableView Swift Version.
The code
import UIKit
class SwipeableViewController: UIViewController {
var swipeAbleView : ZLSwipeableView!
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
swipeAbleView.nextView = {
return self.nextCardView()
}
}
// This is the colors array
var colors : NSArray = NSArray(array: [UIColor.orangeColor() , UIColor.blueColor() , UIColor.greenColor() , UIColor.blackColor() , UIColor.brownColor() , UIColor.magentaColor()])
var v : UIView!
var cardsCount = 6
var cardsIndex = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = UIColor.whiteColor()
view.clipsToBounds = true
swipeAbleView = ZLSwipeableView()
swipeAbleView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)
self.swipeAbleView.alpha = 0.0
UIView.animateWithDuration (0.25, delay: 0.35, options: UIViewAnimationOptions.CurveLinear ,animations: {
self.swipeAbleView.alpha = 1.0
}, completion:nil)
self.view.addSubview(swipeAbleView)
self.swipeAbleView.discardViews()
self.swipeAbleView.loadViews()
}
func nextCardView() -> UIView {
if cardsIndex < cardsCount {
cardsIndex += 1
}
let cardView = CardView(frame: self.swipeAbleView.bounds)
// The error occurs here and the app crashes
cardView.backgroundColor = colors[cardsIndex] as? UIColor
return cardView
}
}
The error occurs when I define the color for the cardView.
The application crashes I get the error.
if cardsIndex < cardsCount {
cardsIndex += 1
}
This condition does not prevent you from going over the bounds, the correct condition would be:
if cardsIndex + 1 < cardsCount {
cardsIndex += 1
}
Although I would consider very strange to change data from viewDidLayoutSubviews.
The clear answer here is to write an extension for integer that clamps the value
extension Int {
func clamp(minRange: Int, maxRange: Int) {
self = min(maxRange, self)
self = max(minRange, self)
}
}
then do this
cardsIndex.clamp(0, cardsIndex + 1)

UIScrollView & UIPageControl - start on specific page in SWIFT

I have implemented an UIScrollView & UIpageControl to display 3 UIViewControllers.
It works very well but I want to start the display on the 2nd UIViewController.
I didn't find yet where is my fault:
var pageControl:UIPageControl!
var scrollView:UIScrollView!
var viewtest1:UIViewController!
var viewtest2:UIViewController!
var viewtest3:UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Initialization of UIScrollView
self.scrollView = UIScrollView()
self.scrollView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height)
self.scrollView.pagingEnabled = true
self.scrollView.scrollEnabled = true
self.scrollView.showsHorizontalScrollIndicator = false
self.scrollView.showsVerticalScrollIndicator = false
self.scrollView.delegate = self
// Initialisation of UIPageControl
self.pageControl = UIPageControl()
pageControl.currentPageIndicatorTintColor = UIColor(red:0.325, green:0.667, blue:0.922, alpha: 1)
pageControl.pageIndicatorTintColor = UIColor.whiteColor()
pageControl.backgroundColor = UIColor.clearColor()
// Add different view to the screen in the order from left to right
self.addChildViewController(self.viewtest1)
self.addChildViewController(self.viewtest2)
self.addChildViewController(self.viewtest3)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(true)
for var i=0; i < self.childViewControllers.count; i++ {
self.loadScrollViewWithPage(i)
}
self.pageControl.currentPage = 0
self.page = 0
self.pageControl.numberOfPages = self.childViewControllers.count
var viewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
if viewController.view.superview != nil {
viewController.viewWillAppear(true)
}
self.scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * CGFloat(self.childViewControllers.count), scrollView.frame.size.height)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
// Load Controllers
var viewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
if viewController.view.superview != nil {
viewController.viewDidAppear(true)
}
}
override func viewWillDisappear(animated: Bool) {
var viewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
if viewController.view.superview != nil {
viewController.viewWillDisappear(true)
}
super.viewWillDisappear(true)
}
override func viewDidDisappear(animated: Bool) {
var viewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
if viewController.view.superview != nil {
viewController.viewDidDisappear(true)
}
super.viewDidDisappear(true)
}
func loadScrollViewWithPage(page:Int){
if page < 0 || page >= self.childViewControllers.count {
return
}
let controller:UIViewController = self.childViewControllers[page] as! UIViewController
if (controller == false) {
return
}
// add the controller's view to the scroll view
if (controller.view.superview == nil) {
var frame:CGRect = self.scrollView.frame
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0
controller.view.frame = frame
self.scrollView.addSubview(controller.view)
}
}
func changePage(sender:AnyObject) -> () {
var senderControl:UIPageControl = sender as! UIPageControl
var page:Int = Int(senderControl.currentPage)
// update the scroll view to the appropriate page
var frame:CGRect = self.scrollView.frame
frame.origin.x = frame.size.width * CGFloat(page)
frame.origin.y = 0
var oldViewController:UIViewController = self.childViewControllers[self.page] as! UIViewController
var newViewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
oldViewController.viewWillDisappear(true)
newViewController.viewWillAppear(true)
self.scrollView.scrollRectToVisible(frame, animated: true)
self.pageControlUsed = true
}
override func scrollViewDidEndScrollingAnimation(scrollView: UIScrollView) {
var oldViewController:UIViewController = self.childViewControllers[self.page] as! UIViewController
var newViewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
oldViewController.viewWillDisappear(true)
newViewController.viewWillAppear(true)
self.page = self.pageControl.currentPage
}
override func scrollViewDidScroll(scrollView: UIScrollView) {
if (self.pageControlUsed == true /*|| _rotating*/) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return
}
var pageWidth:CGFloat = self.scrollView.frame.size.width
var page:Int = Int(floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1)
if (self.pageControl.currentPage != page) {
var oldViewController:UIViewController = self.childViewControllers[self.pageControl.currentPage] as! UIViewController
var newViewController:UIViewController = self.childViewControllers[page] as! UIViewController
oldViewController.viewWillDisappear(true)
newViewController.viewWillDisappear(true)
self.pageControl.currentPage = page
oldViewController.viewDidDisappear(true)
newViewController.viewDidDisappear(true)
self.page = page;
}
}
override func scrollViewWillBeginDragging(scrollView: UIScrollView) {
self.pageControlUsed = false
}
override func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
self.pageControlUsed = false
}
Thank you for your help
In storyboard set the "viewtest2" to "Is Initial View Controller". That will show that viewController first.
Or you can try in appDelegate :
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject :AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var initialViewController = storyboard.instantiateViewControllerWithIdentifier("viewTest2") as UIViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}

Resources