I try to add button overlay on UITableViewController with static cells. But i get this result, button is working, but i not see result of search:
I'm trying to get this result:
I want to button was always at the bottom regardless of scrolling up or down.
In my code i use framework InstantSearch:
import UIKit
import InstantSearch
import WARangeSlider
class SearchTableViewController: UITableViewController {
#IBOutlet weak var resultButton: StatsButtonWidget!
override func viewDidLoad() {
super.viewDidLoad()
resultButton.frame = CGRect(x: 0, y: 0, width: 150, height: 60)
navigationController?.view.addSubview(resultButton)
InstantSearch.shared.registerAllWidgets(in: self.view)
LayoutHelpers.setupResultButton(button: resultButton)
resultButton.addTarget(self, action: #selector(resultButtonClicked), for: .touchUpInside)
}
}
How can i add button overlay on bottom in UITableViewController? Me need use only UITableViewController, not UIViewController with TableView.
You could directly add the button to the UITableView without AutoLayout, and make sure TableView's delegate is the controller, like:
override func viewDidLoad() {
super.viewDidLoad()
self.button.frame = CGRect(x: 0, y: self.tableView.frame.size.height - 50, width: self.tableView.frame.width, height: 50)
self.tableView.addSubview(self.button)
self.tableView.delegate = self
}
Then you are able to fix the button's position by UIScrollView delegate (UITableViewDelegate inherited from this) while TableView is scrolling:
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView == self.tableView) {
let originY = scrollView.frame.size.height - self.button.frame.size.height + scrollView.contentOffset.y
self.button.frame = CGRect(x: 0, y: originY, width: scrollView.frame.width, height: self.button.frame.size.height)
}
}
Alternatively, if you want to position the button by AutoLayout, just define a NSLayoutConstraint property, and bind it to button's bottom space constraint to its super view. Then adjust the constraint's constant value by same mechanism in scrollViewDidScroll function.
You can just add an view at the bottom of your tableview.
override func viewDidLoad() {
super.viewDidLoad()
addResultButtonView()
}
private func addResultButtonView() {
let resultButton = UIButton()
resultButton.backgroundColor = .red
resultButton.setTitle("Hello", for: .normal)
tableView.addSubview(resultButton)
// set position
resultButton.translatesAutoresizingMaskIntoConstraints = false
resultButton.leftAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.leftAnchor).isActive = true
resultButton.rightAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.rightAnchor).isActive = true
resultButton.bottomAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.bottomAnchor).isActive = true
resultButton.widthAnchor.constraint(equalTo: tableView.safeAreaLayoutGuide.widthAnchor).isActive = true
resultButton.heightAnchor.constraint(equalToConstant: 50).isActive = true // specify the height of the view
}
Related
I have a UILabel on the UICollectionViewCell. On the UILabel I've got a UITapGestureRecognizer attached. I'm trying to increase the tap area of the UITapGestureRecognizer on the UILabel when the width of the UILabel increases.
Here is the sample of the code:
class BusCell: UICollectionViewCell {
var bus: Bus!
var tapGesture: UITapGestureRecognizer!
#IBOutlet weak var nameLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
addTapGestureToNameLabel()
}
// MARK: - UI
func addTapGestureToNameLabel() {
tapGesture = UITapGestureRecognizer(target: self, action: #selector(nameLabelDoubleTap(gesture:)))
tapGesture.numberOfTapsRequired = 2
nameLabel.addGestureRecognizer(tapGesture)
nameLabel.isUserInteractionEnabled = true
}
func configure(_ bus: Bus, isStereo: Bool = false) {
self.bus = bus
loadCellUI(bus: bus)
bus.updateBlock = { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.loadCellUI(bus: bus)
}
}
func loadCellUI(bus: Bus) {
nameLabel.frame = CGRect(x: CGFloat(0), y: yPosition, width: 122, height: self.nameLabel.frame.height)
if bus.isStereo {
if bus.index % 2 == 0 {
let frame = nameLabel.frame
nameLabel.frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: 244, height: frame.height)
nameLabel.isHidden = false
// Make the tap frame same as the nameLabel's frame
} else {
nameLabel.isHidden = true
}
} else {
let frame = nameLabel.frame
nameLabel.frame = CGRect(x: frame.origin.x, y: frame.origin.y, width: 122, height: frame.height)
nameLabel.isHidden = false
// Make the tap frame same as the nameLabel's frame
}
}
}
How do I make this work?
A tap gesture recognizer attaches to a view, and responds to taps inside the frame of the view. It doesn't have a tap area of its own. If you increase the size of the label then the tap area should increase in size as well.
I remember reading a recommendation from Apple that a tappable area be at least 40x40 points. You might want to put an invisible view (call it tapView) on top of your label that is slightly larger than the label (You could get the label's frame, and call CGRect.inset(by:) with negative values for all the edges. Use the resulting rect as the tapView's frame, and add the tap view on top of your label.) If you do that then you should put code in your view controller's viewDidLayoutSubviews() method (and any time you change your nameLabel label) to adjust the tapView's frame.
I am playing around with scroll views, and I've run into an issue I'be stuck with. I have a view controller create in Storyboard. The view controller contains a scroll view which fills the entire superview.
I then added the images programmatically to the scroll view. The images do show within the scroll view and paging works just fine. Only problem is the scroll view is set ti fill superview but the image view that hold the images seems like it stops above where the navigation bar would be. How can I have the image view fill the whole view within the scroll view?
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var pagingView: UIPageControl!
var images = [UIImage]()
var frame = CGRect(x: 0, y: 0,width: 0,height: 0)
override func viewDidLoad() {
super.viewDidLoad()
scrollView.delegate = self
scrollView.isPagingEnabled = true
images = [UIImage(named: "Slide1")!, UIImage(named: "Slide2")!, UIImage(named: "Slide3")!, UIImage(named: "Slide4")!]
pagingView.numberOfPages = images.count
// This is where I think I'm having the height problem.
for i in 0..<images.count {
let imageView = UIImageView()
let x = self.view.frame.size.width * CGFloat(i)
imageView.frame = CGRect(x: x, y: 0, width: self.view.frame.width, height: self.view.frame.height)
imageView.contentMode = .scaleAspectFill
imageView.image = images[i]
scrollView.contentSize.width = scrollView.frame.size.width * CGFloat(i + 1)
scrollView.addSubview(imageView)
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pagingView.currentPage = Int(pageNumber)
}
After setting nav bar to hidden, here is the output
Scroll view background color is red
In this case you need to enable the parent view clipsToBounds. Set UIScrollview clipsToBounds property to True.
Programmatically scrollView.clipsToBounds = true
In UIStoryBoard - Click the view->Attributes Inspector
If you would like to see the whole screen, make sure to add the topConstraint of scrollView assigned superView and hide the navigationBar in viewWillAppear,
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.setNavigationBarHidden(true, animated: animated)
}
Make sure to remove the status bar by
override var prefersStatusBarHidden: Bool {
return true
}
Update the Y position of Image.
imageView.frame = CGRect(x: x, y: **self.scrollView.frame.minY**, width: self.view.frame.width, height: self.view.frame.height)
Update the scrollView topConstraint by -20.
Thanks for taking the time to read thus. So basically, I have a UIView in my UIViewController. I want a user to be able to press a button and then the UIView moves from my UIViewController to the my application's window so that the UIView will be above all UIViewControllers. The only thing I could think of doing was
class ViewController: UIViewController {
var window = UIApplication.shared.keyWindow!
var view = UIView()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(view)
}
func tappedAction() {
window.bringSubview(toFront: view)
}
}
but that didn't work. Does anyone have any ideas on how to accomplish this?
You cannot just bring the subview that's in your UIViewController to the front of your UIWindow.
You need to:
Remove the UIView from the UIViewController.
Add the UIView to the main UIWindow.
I chose to do this in this way:
import UIKit
class ViewController: UIViewController {
var customView: UIView!
// Load the main view of the UIViewController.
override func loadView() {
view = UIView()
}
override func viewDidLoad() {
super.viewDidLoad()
// Load the custom view that we will be transferring.
self.customView = UIView(frame: .init(x: 100, y: 250, width: 250, height: 250))
self.customView.backgroundColor = .red
view.addSubview(customView)
// Transfer the view. Call this method in your trigger function.
transfer(self.customView)
}
func transfer(_ view: UIView) {
// Remove the view from the UIViewController.
view.removeFromSuperview()
// Add the view to the UIWindow.
UIApplication.shared.windows.first!.addSubview(view)
}
}
You must set frame fro view at var view = UIView()
then you should add to window window.addSubview(view)
If your view is added on window then window.bringSubview(toFront: view) will work otherwise it will not.
If your view is added on window then you can use bringSubview(toFront:) like that:
Example:
let window = UIApplication.shared.keyWindow!
let view1 = UIView(frame: CGRect(x: window.frame.origin.x, y: window.frame.origin.y, width: window.frame.width, height: window.frame.height))
window.addSubview(view1);
view1.backgroundColor = UIColor.black
let view2 = UIView(frame: CGRect(x: 50, y: 50, width: 100, height: 50))
view2.backgroundColor = UIColor.white
window.addSubview(view2)
UIApplication.shared.keyWindow!.bringSubview(toFront: view1)
So you need to add your view in window:
window.addSubview(view)
I'm trying to add a little bit of extra height to the content of a UIScrollView that is within a WKWebView after it loads by adjusting the contentSize property.
I can modify this property, but it somehow keeps changing back to its original size by the time the next layout/display refresh hits.
To test this even further, I attempted to change contentSize in scrollViewDidScroll. Whenever you scroll to the bottom, you can see for a fraction of a second that it's trying add the extra space and keeps reverting back.
I can't reproduce this issue with UIWebView. It works just fine there. Perhaps some changes were added to WKWebView recently? I'm using Xcode 8 and testing on iOS 9/10.
Given my ineptitude with Dropbox I felt badly so put the attached together to try and help you out. If you change the contentInset property of the WKWebView's scrollView rather than contentSize, this seems to work quite well. I agree with you that while you might be able temporarily to change the content size of the scrollView, it reverts quickly; moreover, there are no delegate methods either for UIScrollView or WKWebView that I can find that you might override to counteract this.
The following sample code has a web page and some buttons that allow you to increase or decrease the top and bottom contentInset and animating you to the appropriate point on the scrollView.
import UIKit
import WebKit
class ViewController: UIViewController {
var webView : WKWebView!
var upButton : UIButton!
var downButton : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let webFrame = CGRect(origin: CGPoint(x: 100, y: 100), size: CGSize(width: self.view.frame.width - 200, height: self.view.frame.height - 200))
webView = WKWebView(frame: webFrame)
webView.load(URLRequest(url: URL(string: <PUT RELEVANT URL STRING (NB - THAT YOU ARE SURE IS VALID) HERE>)!))
webView.backgroundColor = UIColor.red
webView.scrollView.contentMode = .scaleToFill
self.view.addSubview(webView)
func getButton(_ label: String) -> UIButton {
let b : UIButton = UIButton()
b.setTitle(label, for: .normal)
b.setTitleColor(UIColor.black, for: .normal)
b.layer.borderColor = UIColor.black.cgColor
b.layer.borderWidth = 1.0
return b
}
let upButton = getButton("Up")
let downButton = getButton("Down")
upButton.frame = CGRect(origin: CGPoint(x: 25, y: 25), size: CGSize(width: 50, height: 50))
downButton.frame = CGRect(origin: CGPoint(x: 25, y: 100), size: CGSize(width: 50, height: 50))
upButton.addTarget(self, action: #selector(increaseContentInset), for: .touchUpInside)
downButton.addTarget(self, action: #selector(decreaseContentInset), for: .touchUpInside)
self.view.addSubview(webView)
self.view.addSubview(upButton)
self.view.addSubview(downButton)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func increaseContentInset() -> Void {
guard let _ = webView else { return }
webView.scrollView.contentInset = UIEdgeInsetsMake(webView.scrollView.contentInset.top + 100, 0, webView.scrollView.contentInset.bottom + 100, 0)
webView.scrollView.setContentOffset(CGPoint(x: webView.scrollView.contentInset.left, y: -1 * webView.scrollView.contentInset.top), animated: true)
}
func decreaseContentInset() -> Void {
guard let _ = webView else { return }
webView.scrollView.contentInset = UIEdgeInsetsMake(webView.scrollView.contentInset.top - 100, 0, webView.scrollView.contentInset.bottom - 100, 0)
webView.scrollView.setContentOffset(CGPoint(x: webView.scrollView.contentInset.left, y: -1 * webView.scrollView.contentInset.top), animated: true)
}
}
I hope that helps. If you need an answer based specifically on setting the content size then let me know, but I think this is the best option.
I am trying to use this plugin as refresh action : https://github.com/entotsu/PullToBounce
One, issue is I can't understand his explanation.
Explanation given on the github
tableView.frame = yourFrame --> tableView is equal to scrollView.frame in my situation
yourFrame --> I have no idea what it is. The main frame ? Another Frame I have to create ?
bodyView.addSubview(tableViewWrapper) --> bodyView ? Main Frame here ? or Another frame ?
Here is my code for the scrollView for now. Any help on how to implement this plugin using a scrollView made via the storyboard.
class ProfileViewController: UIViewController {
#IBOutlet weak var scrollView: UIScrollView!
func makeMock() {
let headerView = UIView()
headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 64)
headerView.backgroundColor = UIColor.lightBlue
self.view.addSubview(headerView)
let headerLine = UIView()
headerLine.frame = CGRect(x: 0, y: 0, width: 120, height: 8)
headerLine.layer.cornerRadius = headerLine.frame.height/2
headerLine.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.8)
headerLine.center = CGPoint(x: headerView.frame.center.x, y: 20 + 44/2)
headerView.addSubview(headerLine)
}
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.blue
let bodyView = UIView()
bodyView.frame = scrollView.frame
bodyView.frame.y += 20 + 44
self.view.addSubview(bodyView)
let tableViewWrapper = PullToBounceWrapper(scrollView: scrollView)
bodyView.addSubview(tableViewWrapper)
tableViewWrapper.didPullToRefresh = {
NSTimer.schedule(delay: 2) { timer in
tableViewWrapper.stopLoadingAnimation()
}
}
makeMock()
}
override func preferredStatusBarStyle() -> UIStatusBarStyle {
return .LightContent
}
}
One thing, I notice is that there is a View on top of my scrollView that disable me to view it and scroll it. Help here needed please.
Regards,
Hary
Take a look at the Example of this library.
yourFrame is nothing but your tableview class. For example if your tableView Class is named SampleTableView, then it goes like
let tableView = SampleTableView(frame: self.view.frame, style: UITableViewStyle.Plain).
You have to use another class to set up your tableView.