Access values within '<>' sign - ios

I have a gesture recognizer that looks like this:
#objc func handleTap(_ sender: UITapGestureRecognizer) {
var currentImage = sender.view
print(currentImage)
}
And prints out this:
Optional(<UIImageView: 0x7ff72601ddd0; frame = (0 0; 414 414); opaque = NO; gestureRecognizers = <NSArray: 0x600000b541e0>; layer = <CALayer: 0x6000005be0c0>>)
How do I get the value of UIImageView in sender.view?
P.S.
The code that calls the tap recognizer looks like this:
var tap = UITapGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
tap = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:)))
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
imageView.addGestureRecognizer(tap)
imageView.isUserInteractionEnabled = true
}

You can use
if let currentImage = sender.view as? UIImageView {
}
OR directly if 100 % sure
let currentImage = sender.view as! UIImageView
OR
guard let currentImage = sender.view as? UIImageView else { return }
/// then use unwrapped currentImage

Related

tapgesture not working in collectionViewCell, Neither any UIElements is visible on cell which is added by storyboard

I have a collectionViewCell that either plays a video or displays and image.Now the elements in the cell are generated programatically. I added tap gesture to toggle the sound when video play. The gesture recognizer wasn't getting called. I tried to place a button in story and get its action, that also didn't recieve a call. Then, I tried to place a view inside the cell, that also didn't display.
Here is my code with tap gesture:
import UIKit
import AVKit
import AVFoundation
#IBDesignable class CHCollectionImageCell: UICollectionViewCell {
// MARK: Properties
var imgView: UIImageView! = UIImageView()
var screenWidth:CGFloat = 0
var screenHeight:CGFloat = 0
var playerLayer: AVPlayerLayer!
let tapOnCell = UITapGestureRecognizer(target: self, action: #selector (CHCollectionImageCell.changeMuteRegimeVideo))
// MARK: Functions
override func awakeFromNib() {
super.awakeFromNib()
}
func configureCell(insight: InsightModel) {
imgView.removeFromSuperview()
if playerLayer != nil {
playerLayer.removeFromSuperlayer()
playerLayer = nil
}
self.removeGestureRecognizer(tapOnCell)
if insight.isVideo {
guard let unwrappedVideoURLString = insight.videoURL,
let unwrappedVideoURL = URL(string: unwrappedVideoURLString) else {
return
}
let playerItem = AVPlayerItem(url: unwrappedVideoURL)
let player = AVPlayer(playerItem: playerItem)
playerLayer = AVPlayerLayer(player: player)
playerLayer.frame = self.bounds
player.isMuted = false
layer.addSublayer(playerLayer)
addGestureRecognizer(self.tapOnCell)
} else {
imgView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.width)
imgView.image = UIImage(named: "stone")
imgView.contentMode = UIViewContentMode.scaleAspectFill
imgView.clipsToBounds = true
clipsToBounds = true
addSubview(self.imgView)
}
}
/*
#IBAction func tapToTurnOfSound(_ sender: Any) {
if isInsightViedo{
if let unwrappedPlayer = playerLayer.player {
unwrappedPlayer.isMuted = !unwrappedPlayer.isMuted
}
}
//Even Tried adding view as below in the cell
//let tapView = UIView()
//tapView.backgroundColor = ColorCodes.appThemeColor
//self.addSubview(tapView)
//self.bringSubview(toFront: tapView)
//tapView.addGestureRecognizer(tapOnCell)
}
*/
func configureCell() {
imgView.removeFromSuperview()
if playerLayer != nil {
playerLayer.removeFromSuperlayer()
playerLayer = nil
}
self.removeGestureRecognizer(tapOnCell)
imgView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.width)
imgView.image = UIImage(named: "stone")
imgView.contentMode = UIViewContentMode.scaleAspectFill
imgView.clipsToBounds = true
clipsToBounds = true
addSubview(self.imgView)
}
func changeMuteRegimeVideo() {
if let unwrappedPlayer = playerLayer.player {
unwrappedPlayer.isMuted = !unwrappedPlayer.isMuted
}
}
}
Iam doing the same thing in my application by using the following code :
let longPressGesture:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(viewController.longPress(_:)))
longPressGesture.minimumPressDuration = 0.8
longPressGesture.delegate = self
collectionView.addGestureRecognizer(longPressGesture)
and then call the function:
func longPress(_ longPressGestureRecognizer: UILongPressGestureRecognizer) {
if longPressGestureRecognizer.state == UIGestureRecognizerState.began {
let touchPoint = longPressGestureRecognizer.location(in: collectionView)
if eventsTableView.indexPathForRow(at: touchPoint) != nil {
let index = eventsTableView.indexPathForRow(at: touchPoint)//do whatever you want to do with this index
}}}
you can do whatever you want to do in this function. In my case i used this to enlarge the image in the collection view

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

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.)

Drag items placed on UIStackView

I have the code below, and need to drag the views so they can be repositioned. However, on drag, the view simply disappears. How can I make the views draggable while on top of the stack view?
Stack View:
let sView = UIStackView()
sView.axis = UILayoutConstraintAxis.Vertical
sView.distribution = .FillEqually
sView.alignment = UIStackViewAlignment.Center
sView.spacing = 15
sView.backgroundColor = UIColor.redColor()
sView.addArrangedSubview(view1)
sView.addArrangedSubview(view2)
sView.addArrangedSubview(view3)
sView.layoutMarginsRelativeArrangement = true
sView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(sView)
sView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor).active = true
sView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor).active = true
The views; view1, view2, and view3 have similar code as below:
let view1 = UIView()
view1.frame = CGRectMake(30, 50, 50, 80)
view1.backgroundColor = UIColor.blueColor()
view1.layer.cornerRadius = 6
let gesture = UIPanGestureRecognizer(target: self, action: Selector("draggedView:"))
view1.addGestureRecognizer(gesture)
view1.userInteractionEnabled = true
view1.tag = 1
view1.heightAnchor.constraintEqualToConstant(85).active = true
view1.widthAnchor.constraintEqualToConstant(55).active = true
The draggedView function:
func draggedView(gesture: UIPanGestureRecognizer){
let loc = gesture.locationInView(self.view)
let gesturedView = gesture.view
gesturedView!.center = loc
}
Brian,
This code does what I think your looking to do. Obviously you need to go thru it carefully and change variable names, but I sure you up to it!
func draggedView(sender: UIPanGestureRecognizer) {
if (sender.state == UIGestureRecognizerState.Began) {
self.source = editorSVB!.arrangedSubviews.indexOf(sender.view!)! as Int
}
if (sender.state == UIGestureRecognizerState.Changed) {
center = sender.view?.center
let translation = sender.translationInView(sender.view)
center = CGPointMake(center!.x + translation.x, center!.y + translation.y)
sender.view?.center = center!
sender .setTranslation(CGPointZero, inView: sender.view)
}
for blah in self.editorSVB!.arrangedSubviews {
let no = blah.frame.intersect((sender.view?.frame)!)
if (!no.origin.x.isInfinite) {
self.object = editorSVB!.arrangedSubviews.indexOf(blah)! as Int
if (self.object != self.source) {
print("self,object, self.object",self,object, self.source)
self.executable = self.object
}
}
}
}

I want to change the sidebar direction using UIView

I currently have a menu (SideBar) that reveals upon swipe and I want the menu to slide from right to left. I changed the swipe direction to match but I'm not sure how to change the SideBar frame or animation. How can I make the SideBar come from the right instead of left?
//
// SideBar.swift
// SideBarMenu
//
// Created by Alexandre on 30/01/2015.
// Copyright (c) 2015 Alexandre. All rights reserved.
//
import UIKit
//Necessary if we want to specify orptional requirements
#objc protocol SideBarDelegate{
func sideBarDidSelectButtonAtIndex(index:Int)
optional func sideBarWillClose()
optional func sideBarWillOpen()
}
//When an item of the sidebar is selected, and also when the sidebar will open or close
class SideBar: NSObject, SideBarTableViewControllerDelegate {
let barWidth:CGFloat = 150.0
let sideBarTableViewTopInset:CGFloat = 64.0
let sideBarContainerView:UIView = UIView()
let sideBarTableViewController:SideBarTableViewController = SideBarTableViewController()
var originView:UIView!
var animator:UIDynamicAnimator!
var delegate:SideBarDelegate!
var isSideBarOpen:Bool = false
//This init only allocate memory
override init(){
super.init()
}
init(sourceView:UIView, menuItems:Array<String>){
super.init()
originView = sourceView
sideBarTableViewController.tableData = menuItems
setupSideBar()
animator = UIDynamicAnimator(referenceView: originView)
let showGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
showGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Left
originView.addGestureRecognizer(showGestureRecognizer)
let hideGestureRecognizer:UISwipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: "handleSwipe:")
hideGestureRecognizer.direction = UISwipeGestureRecognizerDirection.Right
originView.addGestureRecognizer(hideGestureRecognizer)
}
func setupSideBar(){
sideBarContainerView.frame = CGRectMake(-barWidth - 1, originView.frame.origin.y, barWidth, originView.frame.size.height)
sideBarContainerView.backgroundColor = UIColor.clearColor()
sideBarContainerView.clipsToBounds = false
//Add the sideBar to the originView
originView.addSubview(sideBarContainerView)
//blur back of the ground
//let blurView:UIVisualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: UIBlurEffectStyle.Light))
//blurView.frame = sideBarContainerView.bounds
//sideBarContainerView.addSubview(blurView)
//Setup the menu/tableView
sideBarTableViewController.delegate = self
sideBarTableViewController.tableView.frame = sideBarContainerView.bounds
sideBarTableViewController.tableView.clipsToBounds = false
sideBarTableViewController.tableView.separatorStyle = UITableViewCellSeparatorStyle.None
sideBarTableViewController.tableView.backgroundColor = UIColor.clearColor()
sideBarTableViewController.tableView.scrollsToTop = false
sideBarTableViewController.tableView.contentInset = UIEdgeInsetsMake(sideBarTableViewTopInset, 0, 0, 0)
sideBarTableViewController.tableView.reloadData()
sideBarContainerView.addSubview(sideBarTableViewController.tableView)
}
func handleSwipe(recognizer:UISwipeGestureRecognizer){
if recognizer.direction == UISwipeGestureRecognizerDirection.Right {
showSideBar(false)
delegate?.sideBarWillClose?()
} else {
showSideBar(true)
delegate?.sideBarWillOpen?()
}
}
func showSideBar(shouldOpen:Bool){
animator.removeAllBehaviors()
isSideBarOpen = shouldOpen
//The gravity modifies the open and close speed
let gravityX:CGFloat = (shouldOpen) ? 1 : -1
let magnitude:CGFloat = (shouldOpen) ? 20 : -20
let boundaryX:CGFloat = (shouldOpen) ? barWidth : -barWidth - 1
let gravity:UIGravityBehavior = UIGravityBehavior(items: [sideBarContainerView])
gravity.gravityDirection = CGVectorMake(gravityX, 0)
animator.addBehavior(gravity)
let collisionBehavior:UICollisionBehavior = UICollisionBehavior(items: [sideBarContainerView])
collisionBehavior.addBoundaryWithIdentifier("sideBarBoundary", fromPoint: CGPointMake(boundaryX, 20), toPoint: CGPointMake(boundaryX, originView.frame.size.height))
animator.addBehavior(collisionBehavior)
let pushBehavior:UIPushBehavior = UIPushBehavior(items: [sideBarContainerView], mode: UIPushBehaviorMode.Instantaneous)
pushBehavior.magnitude = magnitude
animator.addBehavior(pushBehavior)
let sideBarBehavior:UIDynamicItemBehavior = UIDynamicItemBehavior(items: [sideBarContainerView])
sideBarBehavior.elasticity = -0.3
animator.addBehavior(sideBarBehavior)
}
func sideBarControlDidSelectRow(indexPath: NSIndexPath) {
delegate?.sideBarDidSelectButtonAtIndex(indexPath.row)
}
}
What you want to do is make your starting frame offscreen to the right instead of the left. You'll also need to change the gravity direction.
in setupSideBar, you'll want to change the first line:
sideBarContainerView.frame = CGRectMake(barWidth + 1, originView.frame.origin.y, barWidth, originView.frame.size.height)
// notice the change in the first value (x position)
// the width +1 puts it offscreen +1.
// Previously it was -width-1 which put it to the left
then, in showSideBar:
// just reversing the gravity
let gravityX:CGFloat = (shouldOpen) ? -1 : 1

How do you transition back and forth between dae scenes?

Here is a slightly modified starter SceneKit project--I added another .dae file named planet.dae. Tap the "ship" to switch to planet.dae. Tap the planet to switch back to ship.dae. Tapping ship does open planet.dae. But when user taps the planet, nothing happens--doesn't seem to recognize my touch. What gives?
import SceneKit
class GameViewController: UIViewController {
override func viewDidLoad() { super.viewDidLoad()
shipScene()
}
func shipScene() {
let scene = SCNScene(named: "art.scnassets/ship.dae")!
let ship = scene.rootNode.childNodeWithName("ship", recursively: true)!
let scnView = self.view as SCNView
scnView.scene = scene
scnView.autoenablesDefaultLighting = true
scnView.allowsCameraControl = true
scnView.backgroundColor = UIColor.blackColor()
let tapGesture = UITapGestureRecognizer(target: self, action: "handleShipTap:")
let gestureRecognizers = NSMutableArray()
gestureRecognizers.addObject(tapGesture)
if let existingGestureRecognizers = scnView.gestureRecognizers {
gestureRecognizers.addObjectsFromArray(existingGestureRecognizers)
}
scnView.gestureRecognizers = gestureRecognizers
}
func handleShipTap(gestureRecognize: UIGestureRecognizer) {
let scnView = self.view as SCNView
let p = gestureRecognize.locationInView(scnView)
if let hitResults = scnView.hitTest(p, options: nil) {
if hitResults.count > 0 {
let result: AnyObject! = hitResults[0]
if result.node!.name!.hasPrefix("ship") {
planetScene()
}
}
}
}
func planetScene() {
let scene = SCNScene(named: "art.scnassets/saturn.dae")!
let ship = scene.rootNode.childNodeWithName("planet", recursively: true)!
let scnView = self.view as SCNView
scnView.scene = scene
scnView.autoenablesDefaultLighting = true
scnView.allowsCameraControl = true
scnView.backgroundColor = UIColor.blackColor()
let tapGesture = UITapGestureRecognizer(target: self, action: "handlePlanetTap:")
let gestureRecognizers = NSMutableArray()
gestureRecognizers.addObject(tapGesture)
if let existingGestureRecognizers = scnView.gestureRecognizers {
gestureRecognizers.addObjectsFromArray(existingGestureRecognizers)
}
scnView.gestureRecognizers = gestureRecognizers
}
func handlePlanetTap(gestureRecognize: UIGestureRecognizer) {
let scnView = self.view as SCNView
let p = gestureRecognize.locationInView(scnView)
if let hitResults = scnView.hitTest(p, options: nil) {
if hitResults.count > 0 {
let result: AnyObject! = hitResults[0]
if result.node!.name!.hasPrefix("saturn") {
shipScene()
}
}
}
}
}
Removing the tapGesture from the planetScene() is all.

Resources