I created an app with Swift 3 and Xcode 8.1. I have a UITableview and a UIView above it that shows and hides by clicking on a button in it. When the UIView appears, the last cell of UITableview does not show completely.
I use following code in button:
func filterShowHide ()
{
if !isShown
{
filterImage.image = UIImage(named: "ME-Filter-re")
self.filterView.isHidden = false
self.tableViewTop.constant = 0
// tableViewHeight.constant = tableViewHeight.constant * 1.5
isShown = true
}
else
{
filterImage.image = UIImage(named: "ME-Filter")
self.tableViewTop.constant = -(self.HeaderView.frame.height) + self.filterBTN.frame.size.height
self.filterView.isHidden = true
isShown = false
// tableViewHeight.constant = tableViewHeight.constant / 1.5
}
UIView.animate(withDuration: 0.25) {
self.view.layoutIfNeeded()
}
}
For more details here's the screenshot of:
Before clicking and After clicking
How can I show the last cell completely?
I think the problem is your tableview height is still the same and it gets pushed down as you update the top constraint.
You should set the table view bottom constraint to bottom of its super view or you can update tableView.contentInset.top with the values you are using for self.tableViewTop.constant
Related
My app deployment target version is iOS 10. and I added navigation bar large title in my app. it is working as per need in above iOS 10. if I try to test this in iOS 10 it is not working. So I am trying to create custom Navigation bar large tile for iOS 10 as well. but i don't know how to achieve this. please guide me. Thanks Advance
if #available(iOS 11.0, *) {
navigationController?.navigationBar.prefersLargeTitles = true
} else {
// need to add here as well
}
In case somebody needs this. Here is how I did it. For me, this is better than the default, because it supports whatever customization you may want from large title (ex. multiline)
In my case my layout looks like this. You can have however you want, but make sure title is not inside of the table view / scroll view.
view
view
large title label
view (this view will stick on top)
view
table view
view
view
In this case, I have scrollViewDidScroll delegate, which checks the scrollView content offset to change the titleLabels top constraint. For me top constraint is 16. Change it to whatever you want to have
extension YourViewController: UITableViewDelegate {
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
let titleHeight = titleLabel.bounds.height
if (scrollView.contentOffset.y <= 0) {
// Title is fully visible - table view is at the top
titleLabelTopConstraint.constant = 16
isLargeTitleHidden = false
} else if (scrollView.contentOffset.y > (titleHeight + 16)){
// Title is not visible at all. Table view is at an unknown position but it is not top
titleLabelTopConstraint.constant = -titleHeight
isLargeTitleHidden = true
} else {
// Title is kind of visible. Not fully hidden or shown.
titleLabelTopConstraint.constant = -scrollView.contentOffset.y + 16
isLargeTitleHidden = false
}
} }
I also have the isLargeTitleHidden to update the nav
var isLargeTitleHidden: Bool = false {
didSet{
if (oldValue != isLargeTitleHidden){
updateNavBar()
}
}
}
func updateNavBar(){
let fadeTextAnimation = CATransition()
fadeTextAnimation.duration = 0.2
fadeTextAnimation.type = CATransitionType.fade
navigationController?.navigationBar.layer.add(fadeTextAnimation, forKey: "fadeText")
if isLargeTitleHidden {
navigationItem.title = titleLabel.text
} else {
navigationItem.title = ""
}
}
NavigationBar have a titleView object where the title is. You can customize a label to go there however you want and make navigationBar.titleView = yourLabel or make a custom UIView all the same.
I am working on a popup view for an app I am making. If you take a second to look at the image attached below, you will see that the top edges are rounded, but the bottom edges are not. This is because I only rounded the edges of the view (it is lowest in the hierarchy). I cannot round the edges of the images (the colorful boxes) because they are tables in a scrolling view. The only solution I can think of is a very ugly one where I mask the bottom edges with a UIImageView that appears once the popup has faded in. Does anyone have a better solution? If so, I would greatly appreciate your help. Also, my scrolling view is not yet functional, so that is not referenced here and the solution (if functional) should work regardless.
My code:
allSeenPopover.layer.cornerRadius = 5
userProfile.layer.cornerRadius = 15
colorBackground.layer.cornerRadius = 15
colorBackground.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
#IBAction func loadUserProfile(_ sender: Any) {
if darken.alpha == 0 {
darken.alpha = 1
self.view.addSubview(userProfile)
userProfile.center = self.view.center
userProfile.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
userProfile.alpha = 0
UIView.animate(withDuration: 0.3) {
self.largeDropShadow.alpha = 0.3
self.userProfile.alpha = 1
self.userProfile.transform = CGAffineTransform.identity
}
}
else {
UIView.animate(withDuration: 0.2, animations: {
self.userProfile.transform = CGAffineTransform.init(scaleX: 1.3, y: 1.3)
self.userProfile.alpha = 0
self.darken.alpha = 0
self.largeDropShadow.alpha = 0
}) { (success:Bool) in
self.userProfile.removeFromSuperview()
}
}
}
The image I was referring to:
Since the view you want rounded is inside a table view cell, you must take care that the view is created added only once per reused cell.
Each time a reused cell scrolls into view, check to see if it has had an imageView subview (using a tag that is unique within the cell is a quick way to make that check). If you don't have one, create it and then configure it for the particular row, otherwise just configure it for the particular row...
(warning, I'm not swift fluent, but the idea should be clear)
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:UITableViewCell = tableView.dequeueReusableCellWithIdentifier(cellReuseIdentifier) as UITableViewCell!
let imageView:UIImageView = cell.viewWithTag(99) as? UIImageView
if (!imageView) {
// this code runs just once per reused cell, so setup
// imageView properties here that are row-independent
imageView = UIImageView()
imageView.tag = 99 // so we'll find this when the cell gets reused
imageView.layer.cornerRadius = 15.0
imageView.clipsToBounds = true
// any other props that are the same for all rows
imageView.frame = // your framing code here
cell.addSubview(imageView)
}
// this code runs each time a row scrolls into view
// so setup properties here that are row-dependent
imageView.image = // some function of indexPath.row
return cell
}
As the title says, I have a custom UITableCell in which I have some UIStackViews. Each of those stacks contains many subviews but I just want to show three of them when the cell is displayed for the first time. If a user wants to see more, there is a [+] button that calls a method that adds the remaining.
The custom cell height is determined via UITableViewAutomaticDimension and it works perfectly for the first display of the cell but when I try to add and remove subviews to the stack, there are views that shouldn't be modified that lose they constraints and the ones that should be displayed doesn't do it in some cases. What I'd like is to show all the UILabels and the height of the cell to be updated.
The method that is called when the button [+] is pressed is the following:
#objc private func changeImage(sender: UIButton) {
let index = (Int(sender.accessibilityValue!)!)
let open : Bool = openItem[index]
let plateStack : UIStackView = plateStacks[index]
let plates : [UILabel] = platesViews[index]
if !open {
sender.setImage(UIImage(named: "less")?.withRenderingMode(.alwaysTemplate), for: .normal)
let nPlatesToAdd = max(platesViews[index].count - 3, 0)
for i in 0..<nPlatesToAdd {
let plate = plates[i + 3]
plateStack.addArrangedSubview(plate)
plate.leadingAnchor.constraint(equalTo: plateStack.leadingAnchor, constant: 0).isActive = true
plate.trailingAnchor.constraint(equalTo: plateStack.trailingAnchor, constant: 0).isActive = true
}
}
else {
sender.setImage(UIImage(named: "more")?.withRenderingMode(.alwaysTemplate), for: .normal)
var i = plateStack.arrangedSubviews.count - 1
while i > 2 {
let view = plateStack.arrangedSubviews[i]
plateStack.removeArrangedSubview(view)
view.removeFromSuperview()
i = i - 1
}
}
openItem[index] = !open
}
The first display of the cell (everything's ok) and after click on the [+] button:
It happened because tableView is already rendered its layout.
You might need to check some causes :
make sure the stackView constraint is properly put to contentView
stackView's distribution must be fill
After you change something that affects tableView height, you can use these code to update cell height without reloading the table:
tableView.beginUpdates()
tableView.endUpdates()
I have a "classic app" with 3 ViewController and a tabBar that I use to change ViewController.
On my first ViewController, I have a button that display a UIView on all the screen, so I hide tabBar with this setTabBarVisible func :
extension UIViewController
{
func setTabBarVisible(visible: Bool, animated: Bool)
{
//* This cannot be called before viewDidLayoutSubviews(), because the frame is not set before this time
// bail if the current state matches the desired state
if (isTabBarVisible == visible) { return }
// get a frame calculation ready
let frame = self.tabBarController?.tabBar.frame
let height = frame?.size.height
let offsetY = (visible ? -height! : height)
// zero duration means no animation
let duration: TimeInterval = (animated ? 0.3 : 0.0)
// animate the tabBar
if frame != nil
{
UIView.animate(withDuration: duration)
{
self.tabBarController?.tabBar.frame = frame!.offsetBy(dx: 0, dy: offsetY!)
return
}
}
}
var isTabBarVisible: Bool
{
return (self.tabBarController?.tabBar.frame.origin.y ?? 0) < self.view.frame.maxY
}
}
That's working, the tabBar is hidden and I see all my UIVIew.
The problem is, I have a UILabel at bottom of the UIView (at the place I usually display the tabBar), and I can't use my TapGesture on my UILabel, nothing is happening.
(if I display the label somewhere else the UITapGesture works good.)
I tried to set zPosition of my tabBar to 0 and zPosition of my UIView to 1 but that's doesn't work either.
How can I get my label clickable at bottom of my view?
Check UILabel.isUserInterration = enable
Make sure that when you hide tabbar, perticular view controller Under bottom bar property is unselect . See atteh imnage.
You can try with programatically also like
ViewController.edgesForExtendedLayout = UIRectEdge.top
make sure is true
label.isUserInteractionEnabled = true
Please refer this link may it help you.
I have a UIView that is will slide down on button tap and then slide back up on another button tap. It slides down perfectly, but when I try to hit the contract button, I can't click it, but it does click a collection view cell that is underneath the view. I can't figure out why it slides down properly but it doesn't function how I expect. Thanks a lot!
#IBAction func onExpandButtonPressed(sender: UIButton) {
let xPosition = expandingView.frame.origin.x
//View will slide to 40 px higher bottom of the screen
let yPosition = expandingView.frame.maxY - 40
let height = expandingView.frame.size.height
let width = expandingView.frame.size.width
UIView.animateWithDuration(0.5, animations: {
self.expandingView.frame = CGRectMake(xPosition, yPosition, height, width)
self.expandButton.hidden = true
self.contractButton.hidden = false
})
}
#IBAction func onContractButtonPressed(sender: UIButton) {
let xPosition = expandingView.frame.origin.x
let yPosition = expandingView.frame.origin.y
let height = expandingView.frame.size.height
let width = expandingView.frame.size.width
UIView.animateWithDuration(1.0, animations: {
self.expandingView.frame = CGRectMake(xPosition, yPosition, height, width)
self.expandButton.hidden = false
self.contractButton.hidden = true
})
}
Perhaps it's because the view has slid over the button. So try to use the following inside the button action that will slide over the non-working button:
self.view.bringSubViewToFront(buttonName)
If you put an NSLog inside your button Action, it can help determine if the function is being called.