Trying to get a UITextView to move content when keyboard is placed over top of itself - uiscrollview

I have a UITextView
#IBOutlet weak var note: UITextView!
note.delegate = self
The text view is inside of a UIScrolLView
#IBOutlet weak var scrollView: UIScrollView!
That I am trying to get to respond to this:
// move the scrollView when the keyboard is presented
NotificationCenter.default.addObserver(self, selector: #selector(Keyboard), name: Notification.Name.UIKeyboardWillHide, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(Keyboard), name: Notification.Name.UIKeyboardWillChangeFrame, object: nil)
that when pressed called this function:
#objc func adjustForKeyboard(_ notification: Notification) {
let userInfo = notification.userInfo!
let keyboardScreenEndFrame = (userInfo[UIKeyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)
if notification.name == NSNotification.Name.UIKeyboardWillHide {
scrollView.contentInset = UIEdgeInsets.zero
} else {
scrollView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
}
scrollView.scrollIndicatorInsets = scrollView.contentInset
}
What I want to happen is when you tap on the UITextView, if the keyboard is going to hide the text view, the content is scrolled up, so that the TextView is always visible. This method works just fine for my UITextFields, but it's not working for the UITextView.
Followed this tutorial, and still not working for me. I'm not sure if he is using UITextView or UITextFields in the video, I think Fields.
OW TO AUTO ADJUST UISCROLLVIEW WHEN KEYBOARD IS UP (SWIFT-4, XCODE-9)
How to adjust a UIScrollView to fit the keyboard

Related

Additional view in NSCollectionViewItem pauses dragEvent in CollectionViewController

I am trying to implement drop delegates on a NSCollectionViewController and having issues using a custom NSCollectionViewItem with an additional View Layer I've added onto the CollectionView Item. FWIW, The additional view is used draw a dashed border to indicate a drop area.
The drag event works fine on this collectionItem, and all other collectionItems without this view when it is hidden, but as soon as the drag event occurs on top of this view, the drag event pauses.
The drag event resumes as soon as the mouse is dragged outside of the view, but nothing happens if I release the drag while the mouse is over the view.
I would love to know what is happening here and how to prevent the custom view from "stealing" the mouse event from the CollectionViewContoller.
Delegate Method on DropViewController
func collectionView(_ collectionView: NSCollectionView, validateDrop draggingInfo: NSDraggingInfo, proposedIndexPath proposedDropIndexPath: AutoreleasingUnsafeMutablePointer<NSIndexPath>, dropOperation proposedDropOperation: UnsafeMutablePointer<NSCollectionView.DropOperation>) -> NSDragOperation {
print("1")
if proposedDropIndexPath.pointee.item <= self.destinationDirectoryArray.count {
if proposedDropOperation.pointee == NSCollectionView.DropOperation.on {
return .move
}
} else if proposedDropIndexPath.pointee.item == self.destinationDirectoryArray.count {
//There's some stuff here validating the URL removed for brevity. It works okay when the focus is outside the view, but happy to add back in if helpful
if proposedDropOperation.pointee == NSCollectionView.DropOperation.on {
return .move
}
}
return[]
}
Configuring Collection View
func configureCollectionView() {
let flowLayout = NSCollectionViewFlowLayout()
flowLayout.minimumInteritemSpacing = 8.0
flowLayout.minimumLineSpacing = 8.0
destinationCollectionView.delegate = self
destinationCollectionView.dataSource = self
destinationCollectionView.register(NSNib(nibNamed: "DestinationCollectionItem", bundle: nil), forItemWithIdentifier: directoryItemIdentifier)
destinationCollectionView.collectionViewLayout = flowLayout
destinationCollectionView.registerForDraggedTypes([.fileURL])
destinationCollectionView.setDraggingSourceOperationMask(NSDragOperation.move, forLocal: true)
}
Collection View Item Setup
class DestinationCollectionItem: NSCollectionViewItem {
#IBOutlet weak var backgroundLayer: NSView!
override func viewDidLoad() {
super.viewDidLoad()
self.highlightState = .none
view.wantsLayer = true
view.layer?.cornerRadius = 8.0
backgroundLayer.isHidden = true
}
}
Custom Border View - Applied custom class in Xib and linked to File's Owner
class BorderedView: NSView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
let path : NSBezierPath = NSBezierPath(roundedRect: self.bounds, xRadius: 10.0, yRadius: 10.0)
path.addClip()
let dashHeight: CGFloat = 2
let dashLength: CGFloat = 7
let dashColor: NSColor = .lightGray
// setup the context
let currentContext = NSGraphicsContext.current!.cgContext
currentContext.setLineWidth(dashHeight)
currentContext.setLineDash(phase: 0, lengths: [dashLength])
currentContext.setStrokeColor(dashColor.cgColor)
// draw the dashed path
let cgPath : CGPath = CGPath(roundedRect: NSRectToCGRect(self.bounds), cornerWidth: 10.0, cornerHeight: 10.0, transform: nil)
currentContext.addPath(cgPath)
currentContext.strokePath()
}
}
Well - I solved this one pretty quick.
While I previously tried adding unregisterDraggedTypes() to the backgroundLayer, the issue turned out to also be occurring on the image layer. I applied it to both the Image and backgroundLayer and it works now.
Collection View Item Setup
class DestinationCollectionItem: NSCollectionViewItem {
#IBOutlet weak var backgroundLayer: NSView!
override func viewDidLoad() {
super.viewDidLoad()
self.highlightState = .none
view.wantsLayer = true
view.layer?.cornerRadius = 8.0
backgroundLayer.isHidden = true
backgroundLayer.unregisterDraggedTypes()
self.imageView?.unregisterDraggedTypes()
self.textField?.unregisterDraggedTypes()
}
}

macOS/SpriteKit: unsupported surface format: LA08 - what error is this?

This is from a macOS 10.12.6 app (Xcode 9.3; Swift 4), and it appears when the app starts running: I get seven of these in the console.
This is the storyboard scene:
In my viewController, I have an outlet for the scrollView; I create an SKView, and add it to the scrollView. (This is the complete code).
let skView: SKView = SKView(frame: NSRect(x: 0, y: 0, width: 2000, height: 1400))
#IBOutlet weak var scrollView: NSScrollView!
override func viewDidLoad() {
super.viewDidLoad()
if let scene = SKScene(fileNamed: "GameScene") {
scene.scaleMode = .resizeFill
scrollView.contentView.addSubview(skView)
skView.presentScene(scene)
}
}
(The purpose of this is to have a SpriteKit view I can scroll; this only seems to work with an imageView embedded in the scrollview.)
This error seems to have no effect on the app or how content is displayed; but I'm curious to know what is is and if I can get rid of it.

How to make a scroll view programmatically in Xcode and add view in it?

I want to make a scroll view programmatically in xcode and want to add anchor constraints using safe area layout guide Auto Layout. And want to add some text views button and map init but could not find any proper way to do this. I have tried many codes. What is the proper code for this?
Please try below code for programmatically create Scroll view and add UIView inside XCode
Swift 4.0
import UIKit
class ViewController: UIViewController {
let scrollView: UIScrollView = {
let view = UIScrollView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let myView: UIView = {
let view = UIView()
view.backgroundColor = .yellow
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
override func viewDidLoad() {
super.viewDidLoad()
// add the scroll view to self.view
self.view.addSubview(scrollView)
// constrain the scroll view to 8-pts on each side
scrollView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 8.0).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 8.0).isActive = true
scrollView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -8.0).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0).isActive = true
//Frame for UIView here
myView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height)
scrollView.addSubview(myView)
}
}

Xcode Swift image zoom gesture

Hope someone can help me. Im trying to make a zoom gesture, so when the image are presented the user can zoom the image with fingers.
My code to present the image are:
// MARK: Show image full screen
func imageTapped(img: AnyObject) {
self.navigationController?.navigationBarHidden = true
let imageView = productImage as UIImageView
let newImageView = UIImageView(image: imageView.image)
newImageView.frame = self.view.frame
newImageView.backgroundColor = .blackColor()
newImageView.contentMode = .ScaleToFill
newImageView.userInteractionEnabled = true
let tap = UITapGestureRecognizer(target: self, action: "dismissFullscreenImage:")
newImageView.addGestureRecognizer(tap)
self.view.addSubview(newImageView)
}
func dismissFullscreenImage(sender: UITapGestureRecognizer) {
sender.view?.removeFromSuperview()
self.navigationController?.navigationBarHidden = false
}
Use UIScrollView and add UIImgeView in scroll view
import UIKit
class ViewController: UIViewController,UIScrollViewDelegate
{
var scrollV : UIScrollView!
var imageView : UIImageView!
override func viewDidLoad()
{
super.viewDidLoad()
self.navigationController?.navigationBarHidden = true
scrollV=UIScrollView()
scrollV.frame = CGRectMake(0, 0, self.view.frame.width, self.view.frame.height)
scrollV.minimumZoomScale=1
scrollV.maximumZoomScale=3
scrollV.bounces=false
scrollV.delegate=self;
self.view.addSubview(scrollV)
imageView=UIImageView()
imageView.image = UIImage(imageLiteral: "neymar.jpg")
imageView.frame = CGRectMake(0, 0, scrollV.frame.width, scrollV.frame.height)
imageView.backgroundColor = .blackColor()
imageView.contentMode = .ScaleToFill
scrollV.addSubview(imageView)
}
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
{
return imageView
}
}
Take gesture programmatically and make its method and write down this code in the method.
pinchRecognizerOnView() is my method name. Take one view or image view inside view controller and add this new view in that.Now apply gesture method on this new view.
func pinchRecognizerOnView(sender: UIPinchGestureRecognizer!) {
sender.view?.transform = CGAffineTransformScale((sender.view?.transform)!, sender.scale, sender.scale)
sender.scale = 1
// its for zoom in out screen
}

How to implement NSTrackingArea's mouseEntered/Exited with animation?

I want to implement a feature that when an user hovers over the specific area, the new view appears with drawer-like animation. And also, when the user leaves the specific area, the drawer should go away with animation. This is exactly what you see when you hover over the bottom of the screen in OS X, where the Dock appears and disappears with animation.
However, if I implement the feature with animation, it does not work properly when you re-enter the specific area before the animation in the mouseExited: is completed. Here's my code:
let trackingArea = NSTrackingArea(rect: CGRectMake(0, 0, 120, 300), options: NSTrackingAreaOptions.ActiveAlways | NSTrackingAreaOptions.MouseEnteredAndExited, owner: self, userInfo: nil)
underView.addTrackingArea(trackingArea) // underView is the dummy view just to respond to the mouse tracking, since the drawerView's frame is changed during the animation; not sure if this is the clean way...
override func mouseEntered(theEvent: NSEvent) {
let frameAfterVisible = CGRectMake(0, 0, 120, 300)
NSAnimationContext.runAnimationGroup({
(context: NSAnimationContext!) in
context.duration = 0.6
self.drawerView.animator().frame = frameAfterVisible
}, completionHandler: { () -> Void in
})
}
override func mouseExited(theEvent: NSEvent) {
let frameAfterInvisible = CGRectMake(-120, 0, 120, 300)
NSAnimationContext.runAnimationGroup({
(context: NSAnimationContext!) in
context.duration = 0.6
self.drawerView.animator().frame = frameAfterInvisible
}, completionHandler: { () -> Void in
})
}
// drawerView's frame upon launch is (-120, 0, 120, 300), since it is not visible at first
In this code, I animate the drawerView by altering its x position. However, as I stated, when you enter the tracking area and then leave the tracking area, the drawer works correctly. But that is not the case if you re-enter the tracking area before the leave-off animation is fully completed.
Of course if I set the animation duration shorter, such as 0.1, this would rarely occur. But I want to move the view with animation.
What I want to do is make the drawerView start to appear again even if the view has not completed disappearing. Is there any practice to do it?
I have a solution that is very similar to your code. What I do different is is that I install the NSTrackingArea not on the view that contains the drawer view, but on the drawer view itself.
This obviously means that the drawer needs to 'stick out' a little bit. In my case the drawer is a small bit visible when it is down because I put an image view in it. If you don't want that then I suggest you just leave the visible area of the drawer empty and translucent.
Here is my implementation:
private enum DrawerPosition {
case Up, Down
}
private let DrawerHeightWhenDown: CGFloat = 16
private let DrawerAnimationDuration: NSTimeInterval = 0.75
class ViewController: NSViewController {
#IBOutlet weak var drawerView: NSImageView!
override func viewDidLoad() {
super.viewDidLoad()
// Remove the auto-constraints for the image view otherwise we are not able to change its position
view.removeConstraints(view.constraints)
drawerView.frame = frameForDrawerAtPosition(.Down)
let trackingArea = NSTrackingArea(rect: drawerView.bounds,
options: NSTrackingAreaOptions.ActiveInKeyWindow|NSTrackingAreaOptions.MouseEnteredAndExited,
owner: self, userInfo: nil)
drawerView.addTrackingArea(trackingArea)
}
private func frameForDrawerAtPosition(position: DrawerPosition) -> NSRect {
var frame = drawerView.frame
switch position {
case .Up:
frame.origin.y = 0
break
case .Down:
frame.origin.y = (-frame.size.height) + DrawerHeightWhenDown
break
}
return frame
}
override func mouseEntered(event: NSEvent) {
NSAnimationContext.runAnimationGroup({ (context: NSAnimationContext!) in
context.duration = DrawerAnimationDuration
self.drawerView.animator().frame = self.frameForDrawerAtPosition(.Up)
}, completionHandler: nil)
}
override func mouseExited(theEvent: NSEvent) {
NSAnimationContext.runAnimationGroup({ (context: NSAnimationContext!) in
context.duration = DrawerAnimationDuration
self.drawerView.animator().frame = self.frameForDrawerAtPosition(.Down)
}, completionHandler: nil)
}
}
Full project at https://github.com/st3fan/StackOverflow-28777670-TrackingArea
Let me know if this was useful. Happy to make changes.
Starting Swift 3. You need to do it like this:
let trackingArea = NSTrackingArea(rect: CGRectMake(0, 0, 120, 300), options: [NSTrackingAreaOptions.ActiveAlways ,NSTrackingAreaOptions.MouseEnteredAndExited], owner: self, userInfo: nil)
view.addTrackingArea(trackingArea)
Credits #marc above!

Resources