Text Cursor out of view when typing - swift

I have multiple PDFKit annotations added into my PDF Document. When the user selects the text annotations to add text, the keyboard appears and the document scrolls upward and the cursor is no long on the screen. I have tried treating the PDF Document as a textfield but that does not work. How can I keep the cursor on screen or centered above the keyboard when the user adds text on the PDF Annotation?
Here is my code:
import UIKit
import PDFKit
class PDFfun: UIViewController {
var pdfView = PDFView()
var textFieldMultiline3 = PDFAnnotation()
let document = PDFDocument(url: Bundle.main.url(forResource: "DOCUMENT", withExtension: "pdf")!)
override func viewDidLoad() {
super.viewDidLoad()
pdfView = PDFView(frame: self.view.frame)
pdfView.document = document
pdfView.autoScales = true
pdfView.backgroundColor = UIColor.lightGray
self.insertMultilineTextBoxIntoOneOneNine(document!.page(at: 119)!)
pdfView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(pdfView)
view.addConstraints([
NSLayoutConstraint(item: pdfView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0),
NSLayoutConstraint(item: pdfView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0),
NSLayoutConstraint(item: pdfView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0),
NSLayoutConstraint(item: pdfView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0)
])
}
func insertMultilineTextBoxIntoOneOneNine(_ page: PDFPage) {
_ = page.bounds(for: .cropBox)
let textFieldMultilineBounds3 = CGRect(x: 27, y: 50, width: 339, height: 510)
textFieldMultiline3 = PDFAnnotation(bounds: textFieldMultilineBounds3, forType: PDFAnnotationSubtype(rawValue: PDFAnnotationSubtype.widget.rawValue), withProperties: nil)
textFieldMultiline3.widgetFieldType = PDFAnnotationWidgetSubtype(rawValue: PDFAnnotationWidgetSubtype.text.rawValue)
textFieldMultiline3.backgroundColor = UIColor.white.withAlphaComponent(1)
textFieldMultiline3.font = UIFont(name: "Arial", size: 15)
textFieldMultiline3.isMultiline = true
page.addAnnotation(textFieldMultiline3)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
if UIDevice.current.orientation.isLandscape {
print("landscape")
pdfView = PDFView(frame: view.frame)
pdfView.autoScales = true
} else {
print("portait")
pdfView = PDFView(frame: view.frame)
pdfView.autoScales = true
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
pdfView.frame = view.frame
}
override var prefersStatusBarHidden: Bool {
return false
}
override var preferredStatusBarStyle: UIStatusBarStyle {
return .lightContent
}
}

Related

Adding views dynamically to UIStackview

I'm trying to add views(or buttons) to UIStackView dynamically.
At first, the UIStackView has no arranged views (vertically), and
after getting from some http response, several views(buttons) are added to UIStackView.
UIStackView is also autolayout to hold a specific area.
I've tried to find dynamic adding example, but failed.
Anyone can show me the examples of adding view onto UIStackView dynamically?
It may help you. Please follow this points:
Add UIScrollView to your UIViewController in storyboard or XIB.
Initiate an NSMutableArray name it arrViews gets server response and adds view in the array.
Initialise UIStackViewpass arrView array in the init method.
After that UIStackView will be added subview of UIScrollView.
Add constraint programmatically to UIStackView. That's it.
if let response = self.serverResponse {
if let body = response.responseBody {
if let view = body.views {
arrViews = createSubViews(view)
}
}
}
let stackView = UIStackView(arrangedSubviews: arrViews)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .vertical
stackView.spacing = 16
stackView.distribution = .fill
self.scrollView.addSubview(stackView)
//constraints
let leading = NSLayoutConstraint(item: stackView, attribute: .leading, relatedBy: .equal, toItem: self.scrollView, attribute: .leading, multiplier: 1.0, constant: 0)
self.scrollView.addConstraint(leading)
let trailing = NSLayoutConstraint(item: stackView, attribute: .trailing, relatedBy: .equal, toItem: self.scrollView, attribute: .trailing, multiplier: 1.0, constant: 0)
self.scrollView.addConstraint(trailing)
let top = NSLayoutConstraint(item: stackView, attribute: .top, relatedBy: .equal, toItem: self.scrollView, attribute: .top, multiplier: 1.0, constant: 0)
self.scrollView.addConstraint(top)
let bottom = NSLayoutConstraint(item: stackView, attribute: .bottom, relatedBy: .equal, toItem: self.scrollView, attribute: .bottom, multiplier: 1.0, constant: 0)
self.scrollView.addConstraint(bottom)
let equalWidth = NSLayoutConstraint(item: stackView, attribute: .width, relatedBy: .equal, toItem: self.scrollView, attribute: .width, multiplier: 1.0, constant: 0)
self.scrollView.addConstraint(equalWidth)
leading.isActive = true
trailing.isActive = true
top.isActive = true
bottom.isActive = true
equalWidth.isActive = true
Hope it will help you. Happy coding :)
I use this code in one of my projects:
let baseFrame = CGRect(origin: .zero, size: CGSize(width: requiredWidth, height: partitionHeight))
for instrument in instruments {
let partitionView = PartitionOnDemand(instrument: instrument, mode: playbackMode, frame: baseFrame, referenceView: partitionsAnimator)
partitionsStackView.addArrangedSubview(partitionView)
let tab = InstrumentInfoTabContainer.instantiate(with: instrument) {
self.focus(on: instrument)
}
tabsStackView.addArrangedSubview(tab)
}
While trying with answers, I happend to find how to work it.
class ViewController: UIViewController {
#IBOutlet weak var stack: UIStackView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func onBtn_Create(_ sender: Any) {
createButton("new button ...")
}
#IBAction func onBtn_Delete(_ sender: Any) {
if let v = stack.arrangedSubviews.last {
stack.removeArrangedSubview(v)
v.removeFromSuperview()
}
}
func createButton(_ title: String) {
let button = UIButton()
button.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
button.backgroundColor = UIColor.blue
button.setTitle(title, for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
stack.addArrangedSubview(button)
}
#objc func buttonAction(sender: UIButton!) {
print("Button tapped")
}
}
And, I anchored to UIStackView, Trailing=0, Leading=0, Top=0, Bottom=8 to TextView.Top
The subviews inside it are intact without any constraints.
Thank you.

App window on top of all windows including others app windows

I like to have my NSWindow top of everything including other app windows. How this is possible?
This is how my custom NSWindow looks like?
override init(contentRect: NSRect, styleMask style: NSWindow.StyleMask,
backing backingStoreType: NSWindow.BackingStoreType, defer flag: Bool) {
super.init(contentRect: contentRect, styleMask: NSWindow.StyleMask.borderless,
backing: NSWindow.BackingStoreType.buffered, defer: false)
// Manage window appearance and size
// this window manages video view controller
self.backgroundColor = NSColor.clear
self.alphaValue = CGFloat(AppSingleton.shared.getVideoOpacity()) / 100
self.isOpaque = false
self.collectionBehavior = .transient
}
And this how I open the NSWindowController from a button action
func openPlayerWindow(url: URL) {
let storyboard:NSStoryboard? = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: Bundle.main)
let playerWindowController = storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "SIPlayerWindowController")) as! PlayerWindowController
if let playerWindow = playerWindowController.window {
playerWindowController.showWindow(nil)
playerWindow.makeKeyAndOrderFront(self)
NSApp.activate(ignoringOtherApps: true)
let videoPlayerController = playerWindow.contentViewController as! VideoPlayerViewController
videoPlayerController.videoFile = url
}
}
PlayerView.swift
import Cocoa
import AVFoundation
class PlayerView: NSView {
override func hitTest(_ point: NSPoint) -> NSView? {
return nil;
}
}
This PlayerView immediately fill with CorePlayer in this func.
VideoViewController.swift
func playVideo(videoFile: URL) {
corePlayer.view().translatesAutoresizingMaskIntoConstraints = false
view.addSubview(corePlayer.view())
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint.init(item: corePlayer.view(), attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1, constant: 0).isActive = true
corePlayer.playURL(videoFile.absoluteURL)
}
Try to use this
self.windowController?.showWindow(nil)
self.makeKeyAndOrderFront(self)
NSApp.activate(ignoringOtherApps: true)
I found the solution
self.ignoresMouseEvents = true;

How do I send subviews to front programmatically? (have tried bringSubview to front)

In my UICollectionViewCell I have an image and a label. The picture takes up the whole cell (which I want) - however, the label is placed behind the image, so it's not visible. I have tried bringSubview(toFront: titleLabel), but nothing happens... I got no clue what to do really, have done a lot of searching.
This is the code for the cell, I don't use Storyboard as you can see (sorry for messy constraints, was testing different solutions to find out if this was the problem)
import UIKit
class BaseCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
setupBasket()
}
func setupViews() {
}
func setupBasket(){
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class VideoCell: BaseCell {
var selectedItemID : String!
static let sharedInstance = VideoCell()
var video: Video? {
didSet {
titleLabel.text = video?.title
setupThumbnailImage()
}
}
func setupThumbnailImage() {
if let thumbnailImageUrl = video?.thumbnail_image_name {
thumbnailImageView.loadImageUsingUrlString(thumbnailImageUrl)
}
}
let thumbnailImageView: CustomImageView = {
let imageView = CustomImageView()
imageView.image = UIImage(named: "taylor_swift_blank_space")
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
return imageView
}()
let titleLabel: UILabel = {
let textView = UILabel()
textView.translatesAutoresizingMaskIntoConstraints = false
textView.text = "Clothes"
textView.textColor = UIColor.lightGray
return textView
}()
let separatorView: UIView = {
let view = UIView()
view.backgroundColor = UIColor(red: 230/255, green: 230/255, blue: 230/255, alpha: 1)
return view
}()
var titleLabelHeightConstraint: NSLayoutConstraint?
let addtoBasket = UIButton(type: .contactAdd)
override func setupViews() {
addtoBasket.frame = CGRect(x: 50, y: 0, width: 20, height: 60)
addSubview(addtoBasket)
addSubview(titleLabel)
addSubview(thumbnailImageView)
addSubview(separatorView)
addSubview(addtoBasket)
titleLabel.superview!.bringSubview(toFront: titleLabel)
//horizontal constraints
addConstraintsWithFormat("H:|-0-[v0]-0-|", views: thumbnailImageView)
//vertical constraints
addConstraintsWithFormat("V:|-1-[v0]-1-|", views: thumbnailImageView)
addConstraintsWithFormat("H:|-0-[v0]-1-|", views: separatorView)
addtoBasket.translatesAutoresizingMaskIntoConstraints = false
addtoBasket.heightAnchor.constraint(equalToConstant: 20).isActive = true
addtoBasket.widthAnchor.constraint(equalToConstant: 20).isActive = true
addtoBasket.centerXAnchor.constraint(equalTo: addtoBasket.superview!.centerXAnchor, constant: 90).isActive = true
addtoBasket.centerYAnchor.constraint(equalTo: addtoBasket.superview!.centerYAnchor, constant: -50).isActive = true
//top constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .top, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1, constant: 8))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .right, relatedBy: .equal, toItem: self, attribute: .right, multiplier: 1, constant: 0))
//right constraint
addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .left, relatedBy: .equal, toItem: self, attribute: .left, multiplier: 1, constant: 20))
//height constraint
titleLabelHeightConstraint = NSLayoutConstraint(item: titleLabel, attribute: .height, relatedBy: .equal, toItem: self, attribute: .height, multiplier: 1, constant: -10)
addConstraint(titleLabelHeightConstraint!)
}
}
Try accessing the labels layer and set its zPosition.
Try titleLabel.layer.zPosition = 1
There was clearly something wrong with the constraints, now working! Thanks

Autolayout constraints set in code not appearing in interface builder

I have a custom view that is set in interface builder with top, leading, trailing, height constraints.
In my Custom view i have a title and a button.
Im trying to add to the title a bottom and centerY constraints.
and to the button width, height, bottom, leading constraints.
When i add any constraint i get an warning in interface builder:
Expected: width=600, height=68.
Actual: width=0, height=0
When i run the code everything works, but i cant see anything in interface builder.
code:
#IBDesignable
class UIHeader: UIView {
var delegate: HeaderDelegate?
private lazy var titleLable: UILabel = {
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
lbl.font = UIFont(name: "Lato-Light", size: 16)
lbl.text = "Title"
return lbl
}()
private lazy var backButton: UIButton = {
let btn = UIButton()
btn.tintColor = UIColor.lightGrayColor()
btn.translatesAutoresizingMaskIntoConstraints = false
let image = UIImage(named: "prev")
if let image = image {
btn.setImage(image.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
}
btn.addTarget(self, action: #selector(UIHeader.OnBackButtonClickLister(_:)), forControlEvents: .TouchUpInside)
return btn
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
}
extension UIHeader {
#IBInspectable
var backButtonImage: UIImage? {
get {
return backButton.imageForState(.Normal)
}
set (newImage) {
backButton.setImage(newImage?.imageWithRenderingMode(.AlwaysTemplate), forState: .Normal)
}
}
#IBInspectable
var title: String? {
get {
return titleLable.text
}
set (newTitle) {
titleLable.text = newTitle
}
}
}
extension UIHeader {
private func setupView() {
backgroundColor = UIColor.whiteColor()
translatesAutoresizingMaskIntoConstraints = false
addSubview(titleLable)
addSubview(backButton)
//add shadow
layer.shadowColor = UIColor(white: 115/255, alpha: 1.0).CGColor
layer.shadowOpacity = 0.5
layer.shadowRadius = 8
layer.shadowOffset = CGSizeMake(0, -1)
NSLayoutConstraint.activateConstraints([
//Title//
//center x
NSLayoutConstraint(item: titleLable, attribute: .CenterX, relatedBy: .Equal, toItem: self, attribute: .CenterX, multiplier: 1.0, constant: 0),
//bottom
NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: titleLable, attribute: .Bottom, multiplier: 1, constant: 12),
//button//
//bottom
NSLayoutConstraint(item: self, attribute: .Bottom, relatedBy: .Equal, toItem: backButton, attribute: .Bottom, multiplier: 1, constant: 4),
//leading
NSLayoutConstraint(item: backButton, attribute: .Leading, relatedBy: .Equal, toItem: self, attribute: .Leading, multiplier: 1, constant: 0),
//width
NSLayoutConstraint(item: backButton, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .Width, multiplier: 1, constant: 40),
//height
NSLayoutConstraint(item: backButton, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .Height, multiplier: 1, constant: 40)
])
}
}
I also tried to add the constraints with:
addConstraint(NSLayoutConstraint)
cant figure out what is the problem.
Thanks
I removed
translatesAutoresizingMaskIntoConstraints = false
and everything works great.

Swift How to add the shouldReceiveTouch on Switch?

I'm trying to add in my project shouldReceiveTouch on the UISwitch but i have a error
class ViewController: UIViewController,UIGestureRecognizerDelegate {
var newSwitch: UISwitch!
var deleteButtonIndex:Int!
var deleteSwitchIndex:Int!
let gesture = UILongPressGestureRecognizer()
func CreateSwitchWithIndex(index:Int) {
let newSwitch = UISwitch()
newSwitch.tintColor = UIColor.blackColor()
newSwitch.on = false
newSwitch.tag = index+1;
newSwitch.addTarget(self, action: Selector("switchSen:"), forControlEvents: UIControlEvents.ValueChanged)
self.view.addSubview(newSwitch)
newSwitch.setOn(false, animated: true)
let newSwitchConstraintL = NSLayoutConstraint(item: newSwitch, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50)
let newSwitchConstraintH = NSLayoutConstraint(item: newSwitch, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50)
let coordX = 368
let coordY = 190
newSwitchConstraintX = NSLayoutConstraint(item: newSwitch, attribute: .CenterX, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 0, constant: CGFloat(coordX))
newSwitchConstraintY = NSLayoutConstraint(item: newSwitch, attribute: .CenterY, relatedBy: .Equal, toItem: view, attribute: .Left, multiplier: 0, constant: CGFloat(coordY))
view.addConstraints([newSwitchConstraintX,newSwitchConstraintY,newSwitchConstraintH,newSwitchConstraintL])
var longPress = UILongPressGestureRecognizer(target: self, action: "menu:")
longPress.minimumPressDuration = 1
longPress.delegate = self
newSwitch .addGestureRecognizer(longPress)
}
func switchSen(sender:UISwitch!) {
if (sender.on == true){
println("on")
}
else{
println("off")
}
}
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
if(touch.view == newSwitch){
return false
}else{
return true
}
}
func menu(gesture:UILongPressGestureRecognizer) {
if(gesture.state == UIGestureRecognizerState.Began){
self.deleteButtonIndex = gesture.view?.tag
self.deleteSwichIndex = gesture.view?.tag
becomeFirstResponder()
var menu = UIMenuController.sharedMenuController()
var deleteItem = UIMenuItem(title: "Delete", action: Selector("delete"))
menu.menuItems = [deleteItem]
var lastLocation:CGPoint = gesture.locationInView(view)
menu.setTargetRect(CGRectMake(lastLocation.x, lastLocation.y, 0.0, 0.0), inView: view)
menu.setMenuVisible(true, animated: true)
}
}
func delete(){
println("Delete")
}
}
I just get this error : fatal error: unexpectedly found nil while unwrapping an Optional value on if(touch.view == newSwitch)
How to add the shouldReceiveTouch on Switch ?
Please try to use this line
let newSwitch: UISwitch!
instead of
var newSwitch: UISwitch!