I'm working on a universal keyboard extension. Currently I want to calculate the height of a single button. The keyboard has 4 rows as the normal iOS keyboard. Because the space between the buttons (y distance) is 5 I calculated: (self.view.frame.height-(5*5))/4 5x5 because the distance to the top and the bottom is included. Now, if I run the app, one button isn't around 1/4 of the screen. Instead the button's height is around 2/3 of the keyboard view. I really can't find my mistake. I hope you can help me with this calculation.
My current code:
import UIKit
class KeyboardViewController: UIInputViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidLayoutSubviews() {
print((self.view.frame.height-25)/4)
addButtons()
}
func addButtons() {
let buttonHeigth = (self.view.frame.height-25)/4
let button = ResizableButton()
button.frame = CGRect(x: CGFloat(5), y: CGFloat(10), width: CGFloat(button.frame.size.width), height: CGFloat(buttonHeigth))
button.addTarget(self, action: #selector(keyPressed(sender:)), for: .touchUpInside)
button.layer.cornerRadius = 10
button.layer.masksToBounds = false
self.scrollView.addSubview(button)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated
}
override func textWillChange(_ textInput: UITextInput?) {
// The app is about to change the document's contents. Perform any preparation here.
}
override func textDidChange(_ textInput: UITextInput?) {
// The app has just changed the document's contents, the document context has been updated.
var textColor: UIColor
let proxy = self.textDocumentProxy
if proxy.keyboardAppearance == UIKeyboardAppearance.dark {
textColor = UIColor.white
} else {
textColor = UIColor.black
}
self.nextKeyboardButton.setTitleColor(textColor, for: [])
}
}
Related
I have a problem with the refresh part. Currently, the function to refresh is OK.
But I want to refresh when the user has finished touching the iphone.
var refController:UIRefreshControl = UIRefreshControl()
override func viewDidLoad() {
super.viewDidLoad()
refController.bounds = CGRect.init(x: 0.0, y: 40.0, width: refController.bounds.size.width, height: refController.bounds.size.height)
refController.addTarget(self, action: #selector(self.webviewRefresh(refresh:)), for: .valueChanged)
refController.attributedTitle = NSAttributedString(string: "refreshing")
WKWebView.scrollView.addSubview(refController)
if contentController.userScripts.count > 0 {
contentController.removeAllUserScripts()
}
...
}
#objc func webviewRefresh(refresh:UIRefreshControl){
refController.endRefreshing()
WKWebView.reload()
}
Currently, Even if user haven't finished touch at this time, when the screen is lowered to a certain height, a refresh is performed on the screen.
But I want to run a refresh when the user has finished touching the screen.
You have to call refresh method in scrollViewDidEndDecelerating delegate method of UIScrollViewDelegate. So import UIScrollViewDelegate in your ViewController Like,
extension YourViewController: UIScrollViewDelegate {
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
if self.refController.isRefreshing {
self.webviewRefresh()
}
}
}
Then your webviewRefresh will be,
#objc func webviewRefresh(){
refController.endRefreshing()
WKWebView.reload()
}
And yourviewDidLoad will be,
override func viewDidLoad() {
super.viewDidLoad()
refController.bounds = CGRect.init(x: 0.0, y: 40.0, width: refController.bounds.size.width, height: refController.bounds.size.height)
refController.attributedTitle = NSAttributedString(string: "refreshing")
WKWebView.scrollView.addSubview(refController)
WKWebView.scrollView.delegate = self
if contentController.userScripts.count > 0 {
contentController.removeAllUserScripts()
}
}
You can use crrefresh library for doing this thing
I am trying to add a delete button as a subview in an image. This is my current structure:
-> class DesignViewController: UIViewController
|
-> class Sticker: UIImageView, UIGestureRecognizerDelegate
|
-> UI button inside the Sticker
Inside Sticker class I have :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let button2 = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button2.backgroundColor = .red
button2.setTitle("Delete", for: .normal)
button2.tag = 23
button2.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.addSubview(button2)
}
#objc func buttonAction(sender: UIButton!) {
print("Button tapped")
}
The buttonAction is not getting called.
When I change self.addSubview(button2) line to :
self.superview?.addSubview(button2)
I can see buttonAction getting called. However I would like to keep the button inside the Sticker view so that when user moves the sticker, the button moves as a subview with it.
Can anyone please help and let me know how I can keep the button inside Sticker view?
By default isUserInteractionEnabled property of UIImageView is set to false. Set it to true and your button will start to respond. You can set it in code as well as in the storyboards.
Also try setting the clipsToBounds property of your imageview to true. It will clip your button if it is going outside of the image bounds. That might be one of the reason that your button is not getting touches.
You should create a protocol delegate for button action. This is code example:
protocol ButtonDelegate: class {
func buttonTapped(button: UIButton)
}
class Sticker: UIImageView {
weak var delegate: ButtonDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(button2)
}
lazy var button2: UIButton = {
let button = UIButton(frame: CGRect(x: 100, y: 100, width: 100, height: 50))
button2.backgroundColor = .red
button2.setTitle("Delete", for: .normal)
button2.tag = 23
button2.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
return button
}()
#objc func buttonAction(sender: UIButton) {
guard let delegate = delegate else { return }
delegate.buttonTapped(button: sender)
}
So, now go to your DesignViewControllerl, add your custom imageview class Sticker. Don't forget to do that "imageView.delegate = self". Then in extension add protocol delegate you've created before. Code example:
class DesignViewController: UIViewController {
private lazy var sticker: Sticker = {
let iv = Sticker(frame: view.bounds)
iv.delegate = self
return iv
}()
override viewDidLoad() {
super.viewDidLoad()
view.addSubiew(sticker)
}
}
extension DesignViewController: ButtonDelegate {
func buttonTapped(button: UIButton) {
// input your action here
}
}
I'm working in swift to make an app the uses the cocoapod framework BBSlideoutMenu to display a menu. I am also using the cocoapod framework ChameleonFramework. What I'm trying to do is make the hamburger button that I'm using change colour when it is opened. I haven't yet implemented it, but I also want to make the bar on top transparent. I've recorded it here so you can see what is happening. Basically, the view only gets updated when I slide away the menu.
Disclaimer: I am aware that using a hamburger menu is viewed as bad code design, unfortunately it is what I need in this app.
Here is my code:
import UIKit
import BBSlideoutMenu
import ChameleonFramework
class ViewController: UIViewController, BBSlideoutMenuDelegate {
#IBOutlet var slideMenu: BBSlideoutMenu!
var button: HamburgerButton! = nil
var menuOpen = false;
let screenSize: CGRect = UIScreen.mainScreen().bounds
let topBar = UIView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height * 0.1))
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib
view.backgroundColor = UIColor.whiteColor()
topBar.backgroundColor = FlatRed()
button = HamburgerButton(frame: CGRectMake(0, 20, 54, 54))
button.addTarget(self, action: #selector(toggleMenu(_:)), forControlEvents:.TouchUpInside)
topBar.addSubview(button)
view.addSubview(topBar)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
slideMenu.setupEdgePan()
slideMenu.slideDirection = .Right
slideMenu.shrinkAmount = 0
slideMenu.slideTravelPercent = 0.87
slideMenu.menuOffset = 0
slideMenu.zoomFactor = 1
slideMenu.springEnabled = false
slideMenu.backgroundColor = FlatRed()
slideMenu.delegate = self
slideMenu.setupEdgePan()
}
func toggleMenu(sender : HamburgerButton!) {
if(menuOpen) {
slideMenu.dismissSlideMenu(animated: true, time: nil)
} else {
slideMenu.presentSlideMenu(true) { () -> Void in
//Runs after menu is presented
}
}
}
func didPresentBBSlideoutMenu(menu: BBSlideoutMenu) {
menuOpen = true
button.changeColor(UIColor.blackColor())
}
func didDismissBBSlideoutMenu(menu: BBSlideoutMenu) {
menuOpen = false
button.changeColor(UIColor.whiteColor())
}
}
I am using this hamburger menu button, which has been created with CoreGraphics and QuartzCore, and have added the following function for change colour.
func changeColor(color: UIColor) {
for layer in [ self.topStroke, self.middleStroke, self.bottomStroke ] {
layer.fillColor = nil
layer.strokeColor = color.CGColor
layer.lineWidth = 4
layer.miterLimit = 4
layer.lineCap = kCALineCapRound
layer.masksToBounds = true
let strokingPath = CGPathCreateCopyByStrokingPath(layer.path, nil, 4, .Round, .Miter, 4)
layer.bounds = CGPathGetPathBoundingBox(strokingPath)
layer.actions = [
"strokeStart": NSNull(),
"strokeEnd": NSNull(),
"transform": NSNull()
]
self.layer.addSublayer(layer)
}
}
Edit: I have tried using setNeedsDisplay on the button, the topBar, and both of them consecutively in the functions toggleMenu, didPresentBBSlideoutMenu and didDismissBBSlideoutMenu and it didn't work
I have also tried calling it on the actual view (self.view)
Try calling setNeedsDisplay the button.
I'm currently tying to familiarise myself with UIKit under Swift and work out the best way of adding UI elements programmatically. However I'm finding that a touch can end way outside the button in which it began yet still register as a TouchUpInside event. The ViewController below is from a single view application and it is straightforward to start a touch on, say, button 17, end it on button 18 and still have buttonAction() declare "Button tapped: 17".
Any idea what I'm missing here?
(Edit: This is under Xcode 6 beta 3 BTW.)
// ViewController.swift
import UIKit
class ViewController: UIViewController {
let scrollView:UIScrollView = UIScrollView()
var GWIDTH:Float = 0.0
var GHEIGHT:Float = 0.0
override func viewDidLoad() {
super.viewDidLoad()
GWIDTH = self.view.bounds.size.width
GHEIGHT = self.view.bounds.size.height
scrollView.frame = CGRectMake(10, 10, GWIDTH-10, GHEIGHT-20)
scrollView.contentSize = CGSize(width:GWIDTH-20, height: 0)
self.view.addSubview(scrollView)
for currentTag in 1...30{
var currentButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
currentButton.frame = CGRectMake(100, scrollView.contentSize.height, 100, 50)
currentButton.backgroundColor = UIColor.greenColor()
currentButton.setTitle("Test Button \(currentTag)", forState: UIControlState.Normal)
currentButton.tag = currentTag
currentButton.addTarget(self, action: "buttonAction:", forControlEvents: UIControlEvents.TouchUpInside)
scrollView.addSubview(currentButton)
scrollView.contentSize = CGSize(width:GWIDTH-20,height:2.0+currentButton.frame.size.height+currentButton.frame.origin.y)
}//next
}// end viewDidLoad()
func buttonAction(sender:UIButton!){
println("Button tapped: \(sender.tag)")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
Okay it's taken a fair bit of digging to get to the bottom of this but a couple of helpful Obj-C links...
UIControlEventTouchDragExit triggers when 100 pixels away from UIButton
How to correctly subclass UIControl?
http://www.bytearray.org/?p=5336 (particularly line 89)
...and it seems that the behaviour is standard due to the touch interface (personally I instinctively find the default zone excessive but I'm sure Apple did its homework) and can be overridden by either sub-classing UIControl or interrogating the position of the control event.
I've opted for the latter and here's an implementation specifically in Swift:
// ViewController.swift
import UIKit
class ViewController: UIViewController {
let buttonCount = 3
override func viewDidLoad() {
super.viewDidLoad()
for currentTag:Int in 1...buttonCount{
var currentButton = UIButton.buttonWithType(UIButtonType.System) as UIButton
currentButton.frame = CGRectMake(50, Float(currentTag*50), 120, 50)
currentButton.backgroundColor = UIColor.greenColor()
currentButton.setTitle("Test Button \(currentTag)", forState: UIControlState.Normal)
currentButton.contentEdgeInsets = UIEdgeInsets(top:3,left:6,bottom:3,right:6)
currentButton.tag = currentTag
currentButton.addTarget(self,
action: "btn_TouchDown:",
forControlEvents: UIControlEvents.TouchDown)
currentButton.addTarget(self,
action: "btn_TouchDragExit:",
forControlEvents: UIControlEvents.TouchDragExit)
currentButton.addTarget(self,
action: "btn_TouchUpInside:event:",
forControlEvents: UIControlEvents.TouchUpInside)
currentButton.sizeToFit()
self.view.addSubview(currentButton)
}//next
}// end viewDidLoad()
func btn_TouchDown(sender:UIButton!){
println("TouchDown event: \(sender.tag)\n")
}
func btn_TouchDragExit(sender:UIButton!){
println("TouchDragExit event: \(sender.tag)\n")
}
func btn_TouchUpInside(sender:UIButton!,event:UIEvent!){
println("TouchUpInside event: \(sender.tag)")
var currentTouch:CGPoint = event.allTouches().anyObject().locationInView(sender)
println( "Point: \(currentTouch.x), \(currentTouch.y)\n" )
if currentTouch.x > sender.frame.width{return}
if currentTouch.x < 0 {return}
if currentTouch.y > sender.frame.height{return}
if currentTouch.y < 0 {return}
println("Event ended within frame!")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
I have a UIButton. I want it to generate at random places on the screen. It returns no errors, and runs, but nothing shows up on the screen. I tried hard-coding the values, and that works. I am using Swift.
CODE:
import UIKit
class ViewController: UIViewController {
let changingPoint = UIButton()
let dot = UIImage(named: "sponsor-dot.png")
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
changingPoint.setImage(dot, forState: .Normal)
changingPoint.addTarget(self, action: "pointPressed:", forControlEvents: .TouchUpInside)
changingPoint.frame = CGRectMake(CGFloat(arc4random()%(320)), CGFloat(arc4random()%(568)), 150, 150)
self.view.addSubview(changingPoint)
}
func pointPressed(sender: UIButton!) {
changingPoint.frame = CGRectMake(CGFloat(arc4random()%(320)), CGFloat(arc4random()%(568)), 150, 150)
println()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I Believe that you not set a background color for the button.
changingPoint.backgroundColor = UIColor.blackColor() //or any other color that you want
I don't think your image is loading properly. Try printing dot to see if it is null:
println("image: \(dot)")