I can't see suggestions when typing.. i have tableview cell and textfield in it.
I'm using MPGTextField library, swift version(swift 2 supported).
Any solution for this?
Code:
#IBOutlet weak var articleField: MPGTextField_Swift!
override func viewDidLoad() {
super.viewDidLoad()
articleField.mDelegate = self
}
func dataForPopoverInTextField(textfield: MPGTextField_Swift) -> [Dictionary<String, AnyObject>] {
return articles
}
func textFieldShouldSelect(textField: MPGTextField_Swift) -> Bool{
return true
}
func textFieldDidEndEditing(textField: MPGTextField_Swift, withSelection data: Dictionary<String,AnyObject>){
print(data["CustomObject"])
}
In the MPGTextField-Swift.swift you'll find a function provideSuggestions()
In this function you'll find a line
self.superview!.addSubview(tableViewController!.tableView)
Replace this line with
//BUG FIX - SHOW ON TOP
//self.superview!.addSubview(tableViewController!.tableView)
let aView = tableViewController!.tableView
var frame = aView.frame
frame.origin = self.superview!.convertPoint(frame.origin, toView: nil)
aView.frame = frame
self.window!.addSubview(aView)
////
I've forked MPGTextField repository, made necessary changes for demo purpose.
You can find my repo at https://github.com/rishi420/MPGTextField
Note: This repo needs Xcode 7.1.1 to compile. Feel free to contribute. :-]
I can't really tell what's going on. Is the autocomplete box showing but just cut off at the bottom of the tableViewCell? If so, try setting clipsToBounds to false on the tableViewCell, and maybe even its content view too.
Touch events are not by default recognized for areas outside of a view's frame. To route the taps to the suggestion, you'll have to subclass the tableViewCell and override hitTest
A solution for this would be set the cell height when the cell is selected:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if tableView.indexPathForSelectedRow == indexPath {
return self.selectedCellHeight
}
return self.unSelectedCellHeight
}
You only have to set the unselectedCellHeight and the selectedCellHeight
The beginUpdates() and endUpdates() will update the cell height and animate it.
Related
I am using a UIViewController which contains a ContainerView. Inside the ContainerView I have a UITableViewController. I have a PanGestureRecognizer in my UIViewController which I use for dismissing it. Now the problem I have is that when I pan to close the UIViewController, the TableViewCells inside UITableViewController that are touched become briefly highlighted.
I have disabled scrolling in my tableview as I don't need it.
I added this to my pan gesture handler's .began but it didn't have any effect:
myTableView.isUserInteractionEnabled = false
I also tried:
myGestureRecognizer.cancelsTouchesInView = true
but the touches are still passed to the TableView and cause the cells to become highlighted. Is there any solution for this?
I ended up using this:
myGestureRecognizer.delaysTouchesBegan = true
It may not be useful in every situation, but for my TableView it prevents the highlights from happening.
You could try immediately deselecting rows that are selected in the delegate method for didSelectRow.
extension MyViewController: UITableViewDelegate {
public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
}
}
Will prevent cells from being highlighted when selected. From my experience, this is somewhat common practice.
EDIT: My mistake, misread the question. In which case, you could consider using the tableView's scrollView delegate to determine when you're scrolling, and disable interaction on the individual cells like so:
class ViewController: UIViewController {
private var areCellsDisabled = false {
didSet {
tableView.reloadData()
}
}
// Rest of your view controller logic here...
}
extension ViewController: UITableViewDelegate {
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
areCellsDisabled = true
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
areCellsDisabled = false
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure/dequeue the cell, etc.
if areCellsDisabled {
cell.isUserInteractionEnabled = false
} else {
cell.isUserInteractionEnabled = true
}
return cell
}
}
This might be taking a hammer to the problem, though. Let me know if it helps.
This question already has answers here:
Open UITableView edit action buttons programmatically
(5 answers)
Closed 5 years ago.
I have made a few custom edit actions on my tableviewcell. It works fine when I swipe, but I was wondering if there was any way to trigger these actions when I tap the cell. Also, I have seen lots of people answer similar questions with just,
tableView.setEditing(true, animated: true)
though this is not the solution I am looking for. I want the actions to immediately get displayed without the press of another button.
Short answer is - there is no such way.
However, if you really need something like that, you can mimic this behaviour, though it requires lot more implementation and state handling on your own.
Here is a quick and very dirty solution, which overrides touchesEnded method of your custom cell. Remember to set up Cell as a dynamic prototype of the cell in your table view in relevant storyboard and set its reuse identifier to identitifer.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CellDelegate {
#IBOutlet weak var tableView: UITableView?
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "identifier") as? Cell else {
return UITableViewCell()
}
cell.textLabel?.text = "\(indexPath.row)"
cell.indexPath = indexPath
cell.delegate = self
return cell
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
return nil
}
func doAction(for cell: Cell) {
let indexPath = cell.indexPath
print("doing action for cell at: \(indexPath!.row)")
// your implementation for action
// maybe delete a cell or whatever?
cell.hideFakeActions()
}
}
protocol CellDelegate: class {
func doAction(for cell: Cell)
}
class Cell: UITableViewCell {
weak var delegate: CellDelegate?
var indexPath: IndexPath!
#IBOutlet weak var buttonAction1: UIButton?
#IBOutlet weak var constraintButtonFakeActionWidth: NSLayoutConstraint?
override func awakeFromNib() {
self.constraintButtonFakeActionWidth?.constant = 0
}
override func touchesEnded(_ touches: Set<UITouch>,
with event: UIEvent?) {
guard let point = touches.first?.location(in: self) else {
return
}
if self.point(inside: point, with: event) {
print("event is in cell number \(indexPath.row)")
self.showFakeActions()
}
}
func showFakeActions() {
self.constraintButtonFakeActionWidth?.constant = 80
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}
}
func hideFakeActions() {
self.constraintButtonFakeActionWidth?.constant = 0
UIView.animate(withDuration: 0.3) {
self.layoutIfNeeded()
}
}
#IBAction func fakeAction() {
delegate?.doAction(for: self)
}
}
So how does it work? Each cell is a UIView which inherits from abstract UIResponder interface. You can override its methods to do actions on your own on behalf of events that are dispatched to them. This is the first step where you override touchesEnded.
Take a look at the screenshot from interface builder - you have to hook up the constraint.
I've also implemented the delegate which returns nil for all edit actions of the cells, so they don't interfere with your workaround.
Next, you set up a custom delegate to get a callback from the cell. I also attached IndexPath to the cell for the convenience of managing data in the dataSource, which you have to implement.
Remember that this code lacks a lot, like prepareForReuse method implementation. Also, you probably want to do additional checks in touchesEnded override which would guarantee that this delegate callback is not fired more than once per touch and prevent multiple touches. The logic for disabling user interaction on a cell is not implemented here as well. And interface requires fine-tuning (like text appears to be squashed during the animation).
I'm having trouble getting my text to stay within the width of the screen. I shrunk the text and don't want to make it any smaller (please see below):
Would it be better, in terms of having an adaptive layout that fits the screen, to use Storyboard instead of doing it programmatically?
This is my existing code for the Left View Controller:
import UIKit
protocol LeftViewControllerDelegate {
func leftUnitSelected(index: WUnit)
func leftDataChanged(text: String)
}
class LeftViewController: UIViewController,UITableViewDelegate,UITextFieldDelegate {
#IBOutlet weak var leftTextField: UITextField!
var dataArray: [String] = []
var delegate: LeftViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.dataArray = ["Litre", "MilliLitre", "Fluid Ounce (US)", "Fluid Ounce (UK)", "Teaspoon (US)", "Teaspoon (UK)", "Tablespoon (US)", "Tablespoon (UK)", "Cup (US)", "Cup (UK)", "Pint (US)", "Pint (UK)", "Quart (US)", "Quart (UK)", "Gallon (US)", "Gallon (UK)"]
NSNotificationCenter.defaultCenter().addObserver(self, selector: "textFieldTextDidChangeOneCI:", name: UITextFieldTextDidChangeNotification, object: self.leftTextField)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//MARK: UITableView Datasource
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
cell.textLabel!.text = self.dataArray[indexPath.row]
cell.textLabel!.font = UIFont(name: cell.textLabel!.font.fontName, size:12) // Change the font size as per your requirement
cell.imageView!.image = UIImage(named: "20x20_empty-round-radiobutton-choice-ui")
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 32
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cell.imageView!.image = UIImage(named: "20x20_empty-round-radiobutton-choice-ui")
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
cell.imageView!.image = UIImage(named: "20x20_round-choice-radiobutton-ui")
if let delegate = delegate {
delegate.leftUnitSelected(WUnit(rawValue: indexPath.row)!)
}
}
func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String {
return "From"
}
//MARK:
func setText(text: String) {
self.leftTextField.text = text
}
func textFieldTextDidChangeOneCI(notification: NSNotification) {
let textfield: UITextField = notification.object! as! UITextField
if Double(textfield.text!) > 0.0 {
if let delegate = delegate {
delegate.leftDataChanged(textfield.text!)
}
}
}
func text() -> String {
return self.leftTextField.text!
}
}
Thanks for any suggestions!
A storyboard-based approach handles many of the necessary details to support an adaptive UI.
Apart from that, you could reconsider your design. It's not really a native design for iOS, since iOS doesn't have radio buttons or horizontally compact split tableviews.
You could take a look at existing unit conversion apps to get a feel for how they let users select a unit.
One suggestion is to only ask for one unit (at a time). Once you know one unit, you could predict the second unit to save the user from having to select that likely choice.
Either way, you should think in terms of trait classes and how your UI would adapt (e.g., modal, popover, split view) for different devices.
As for the UI, you could do this via a picker, a tableview's checkmark accessory view, or a custom control. Just remember that the more familiar and intuitive the UI appears to a user, the less likely a user will be puzzled by how to use your app.
The less choices you present, the better for the user. For example, if someone is located in the UK, they likely wouldn't need to convert to a US measure. If you absolutely need to present all the possible choices, consider separating measures into different sections (by country or system).
It seems that you have already designed ui in tableview cell & you are setting its height programatically.You can set the lines property of the label from the interface builder in attributes inspector to appropriate lines so that your text will get adjusted accordingly.Also make sure to increase tableview row size from size inspector so that your cell fits accordingly
I am programmatically adding a UITableView as a subview of a view that uses UIView.animateWithDuration to expand the view when a button is clicked from a single point to a full window. Basically, a box that starts as a point and expands to full size with an animation. I am having difficulties getting the table to populate with cells. At first, a cell was being created, but would disappear after quickly after the animation completed, after playing around with it, I have gotten the cell to remain after the animation is complete, but now the cell disappears when I tap on it. I don't understand what is going on here. Can someone please help?
Here is my code. Note, I have removed what I believe to be irrelevant to this problem to make the code easier to read.
class PokerLogSelectionView: UIViewController {
let logSelectionTableViewController = LogSelectionTableViewController()
let logSelectionTableView = UITableView()
// Irrelevant class variables removed
init(btn : PokerLogSelectionButton){
// Irrelevant view initialization code removed
// Display the subviews
self.displayLogListScrollView()
}
func displayLogListScrollView() {
// Frame is set to (0,0,0,0)
let frame = CGRect(x: self.subviewClosed, y: self.subviewClosed, width: self.subviewClosed, height: self.subviewClosed)
logSelectionTableView.delegate = self.logSelectionTableViewController
logSelectionTableView.dataSource = self.logSelectionTableViewController
// Set the frame of the table view
logSelectionTableView.frame = frame
// Give it rounded edges
logSelectionTableView.layer.cornerRadius = 10
// Remove the cell divider lines
logSelectionTableView.separatorStyle = UITableViewCellSeparatorStyle.None
logSelectionTableView.backgroundColor = logSelectionViewContentScrollViewColor
self.view.addSubview(logSelectionTableView)
//self.logSelectionTableView.reloadData()
//self.addChildViewController(logSelectionTableViewController)
}
override func viewDidAppear(animated: Bool) {
// Create animation
let timeInterval : NSTimeInterval = 0.5
let delay : NSTimeInterval = 0
UIView.animateWithDuration(timeInterval, delay: delay, options: UIViewAnimationOptions.CurveEaseOut, animations: {
// Irrelevant code removed
// Set the size and position of the view and subviews after the animation is complete
self.view.frame = CGRect(x: self.frameXopen, y: self.frameYopen, width: self.frameWopen, height: self.frameHopen)
self.logSelectionTableView.frame = CGRect(x: self.subviewXopen, y: self.svYopen, width: self.subviewWopen, height: self.svHopen)
}, completion: { finished in
self.addChildViewController(self.logSelectionTableViewController)
})
}
}
class LogSelectionTableViewController : UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.registerClass(LogSelectionCell.self, forCellReuseIdentifier: "logCell")
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return pokerLibrary.logNames.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 20
}
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("Selected row: \(indexPath.row)")
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell : LogSelectionCell = self.tableView.dequeueReusableCellWithIdentifier("logCell") as? LogSelectionCell {
cell.selectionStyle = UITableViewCellSelectionStyle.None
cell.textLabel!.text = pokerLibrary.logNames[indexPath.row].name
return cell
}
fatalError("Could not dequeue cell of type 'LogSelectionCell'")
}
}
Note: I can see the tableview after the animation is complete. The color is different than the view in the background view and the tableview does not disappear, just the cell. I expect there to be 1 cell, and I have printed out the number of rows in section 0 and it always returns 1.
Thanks for the help!
Edit:
Here is a screenshot of the view hierarchy before the cell disappears.
Here is a screenshot of the view hierarchy after I tap the cell and it disappears.
I overrode the touchesBegan method in my custom cell and did not call its superclass method. This stopped the cell from disappearing when I tap it, but it still disappears when I scroll the tableView.
I've googled for hours and have tried a handful of tutorials, but haven't been able to get this working:
I have a TableView, and I want to make it so pressing on a cell presents a popup that has a date picker.
I have my custom viewcontroller with the date picker presenting (popping up from the bottom), but it takes up the entire screen. Thoughts? I found one mention of this exact issue while googling but the solution didn't work.
One possibility is to overlay a subview (object of UIView) (with a date picker and a done button) on top of your tableview. Then use .hidden feature of the subview to hide/show the view. The following is an example of the tableviewcontroller. When setting up the storyboard make sure that the subview has the layout constraints so the date picker is positioned properly. I used the "resolve auto layout issues" and it worked good. Unless you do special processing the subview will get positioned at the bottom of the rows. If you have a lot of rows the aubview will get clipped or hidden completely. So it is better to position the subview at the relative to the bottom of the page in your auto layout.
Here is a simple example that worked well for me. In viewDidLoad the subview is hidden. When you click on any row it will show the subview and the date picker. When you press done it will hide the subview again.
import UIKit
class TableViewController: UITableViewController {
#IBAction func doneButton(sender: UIButton) {
// process the date using datePickerOutlet properties
subView.hidden = true // hide the subview and its components
}
#IBOutlet weak var subView: UIView!
#IBOutlet weak var datePickerOutlet: UIDatePicker!
#IBAction func datePicker(sender: UIDatePicker) {
}
override func viewDidLoad() {
super.viewDidLoad()
subView.hidden = true // hide the subview and its components
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 3
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("\(indexPath.row)")
subView.hidden = false // show the subview and its components
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel!.text = "\(indexPath.row)"
return cell
}
}
Alternatively, put it in a UIAlertView(). At least it will be centered. It's going to be tough to combine a table and a picker on a small screen, like let's say a 4S.
I think this should work:
override var preferredContentSize: CGSize {
get{
// Checks if it is currently presenting
if presentingViewController != nil {
return (datePicker.sizeThatFits(presentingViewController!.view.bounds.size))
}
return super.preferredContentSize
}
set{ super.preferredContentSize = newValue }
}
This code goes under the View controller for the popup.
Basically what it does is to set the width of the popup to the minimum size required for the date picker.
Got it from the iTunes U tutorial by Paul Hegarty