Context:
In order to get a shadow on all my tableview cells I have added a shadow to my transparent table view. This to avoid shadows from separate cells falling onto other cells. However, this also means everything in the table view gets a shadow. As I want to have a shadowless remove button appear without shadow when the cell is swiped to the right, I was wondering:
Question:
Can I eliminate the shadow from one specific subview in a UIView with a shadow?
Specifically without having to take it out of the table view in this case. I like to keep it in the tableview so that it scrolls with the table view.
Adding shadow to tableView
self.tableView.clipsToBounds = false
self.tableView.layer.shadowOffset = CGSizeMake(5,5)
self.tableView.layer.shadowColor = UIColor.blackColor().CGColor
self.tableView.layer.shadowRadius = 5
self.tableView.layer.shadowOpacity = 1
and then when the cell is swiped away I simply add the button
let cellFrame = tableView.rectForRowAtIndexPath(indexPath)
var buttonFrame = CGRectInset(cellFrame,10,8)
buttonFrame.size.width = 150
let buttonView = UIButton(frame: buttonFrame)
buttonView.setTitle("Remove", forState: UIControlState.Normal)
buttonView.backgroundColor = UIColor.redColor()
tableView.insertSubview(buttonView, atIndex: 0)
//some animation to move the cell out of the way
Related
I'm trying to shift down my searchbar to align with the bottom of its parent cell in a collection view.
if(searchBarCellId == widgets[indexPath.item]){
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: searchBarCellId, for: indexPath) as! SearchBarCell
cell.backgroundColor = UIColor.white
cell.searchBar.backgroundImage = UIColor.white.image()
cell.searchBar.tintColor = UIColor.gray
let textFieldInsideSearchBar = cell.searchBar.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.backgroundColor = UIColor.lightGray
return cell
}
Is there a way to align the searchbar with the bottom cell of the cell programatically?
The custom xib editor does not allow me add constraints.
Updated with the full solution
Added constraint using editor
Edited codes:
if(searchBarCellId == widgets[indexPath.item]){
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: searchBarCellId, for: indexPath) as! SearchBarCell
cell.backgroundColor = UIColor.white
let frameWidth = UIScreen.main.bounds.width
let frameHeight = UIScreen.main.bounds.width*0.2
cell.searchBar.frame=CGRect(x: 0, y: frameHeight*0.47, width: frameWidth*0.7, height: frameHeight*0.5)
cell.searchBar.backgroundImage = UIColor.white.image()
cell.searchBar.tintColor = UIColor.gray
let textFieldInsideSearchBar = cell.searchBar.value(forKey: "searchField") as? UITextField
textFieldInsideSearchBar?.backgroundColor = UIColor.lightGray
return cell
}
InterfaceBuilder's .xib editor does indeed let you specify constraints. You need to turn on "Use Auto Layout" in the File Inspector (first tab in the right side pane).
Alternatively, you may set up constraints programmatically.
Edited for more info
How to add a bottom constraint to the search bar:
Select just the search bar. Then tap on the Add New Constraints button at bottom right of the .xib window (it looks like a tie fighter icon). Tap on the thin red line below the center box in the graphic, set the value to something appropriate (probably close to 0) and verify the view you're binding it to by pulling down the popup next to that value. Then tap the Add 1 Constraint button. That should bind the bottom of the search bar to the bottom of its parent view.
So the point is you just want to set up constraints for the search box relative to its immediate parent, which will be the view of the cell in your case, regardless that the xib doesn't know it's going to be for a cell.
I'm trying to add a 50% black alpha view on every collection view cell. The collection view cells have a background photograph and text on top. Would like the overlay view to be in between the two.
In my cellForItemAt method, I use the following:
let overlayView = UIView()
overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.frame = cell.bounds
cell.addSubview(overlayView)
The problem is as i scroll down, then up, the overlay keeps adding, making the alpha much darker than 50%. Additionally, the overlayView is being added on top of my text (I need it below the text.)
How can I prevent the overlay from adding multiple times, and adding it in between the correct layers of the cell?
UITableView has a method of reusing cells to make it more efficient (keeping only the required cells in memory). Because of this the reused cell may already have this subview, so calling addSubview again causes another view to be added on top of it.
Here is how to solve this:
Move addSubview(overlayView) to the layoutSubviews() method inside your cell subclass.
override func layoutSubviews() {
super.layoutSubviews()
addSubview(overlayView)
}
Remove the overlay view in the prepareForReuse() method inside your cell subclass.
override func prepareForReuse() {
super.prepareForReuse()
overlayView.removeFromSuperview()
}
Note that this requires you to define the overlay view in the cell's subclass (which you should probably do since the cell itself should be responsible for its own subviews).
This happens because your cells are dequeued and reused multiple times, therefore, you are adding multiple layers.
Put this code inside your cell's class
override func awakeFromNib() {
super.awakeFromNib()
let overlayView = UIView()
overlayView.backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.5)
overlayView.frame = self.bounds
self.addSubview(overlayView)
}
Or if you want to achieve the same result you can set black backgroundColor and set imageView's alpha to 50%
cell.backgroundColor = .black
cell.imageView.alpha = 0.5
Avoid adding this in cellForItem. The cells are reused, hence if you keep adding the view it would add one top of another. On reusing the cell the previously added view is not removed. Instead you can add the view in Prototype cell or XIB and set its alpha to whatever you want. Or if you are creating the cell programatically you can it in awakeFromNib()
I am trying to do something like this:
When the user clicks "Add Page," a new grouping shows up below it. Now, I decided to use Table View cells in order to achieve this. After following various tutorials and looking up similar Q&As, I am able to add cells on button click with UILabel and have the cell height be dynamic depending on the content but now I am trying to figure out how to add ImageViews and place buttons within a cell.
I've created a custom cell class:
class PageCell : UITableViewCell {
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.selectionStyle = UITableViewCellSelectionStyle.none
setupViews()
}
...
... // other random code here
let imgView : UIImageView = {
let imgview = UIImageView()
imgview.frame = CGRect(x: 100, y: 150, width: 150, height: 140)
imgview.tintColor = UIColor(red: 0.73, green: 0.2, blue: 0.3, alpha: 1.0)
imgview.translatesAutoresizingMaskIntoConstraints = false
return imgview
}()
func setupViews() {
addSubview(pageLabel) // the label that I got working
addSubview(imgView) // can't get this working
...
// constraint info here
}
}
And back in my TableViewController:
class TakePhotosVC: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(PageCell.self, forCellReuseIdentifier: "cellID")
}
// return the actual view for the cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let pagecell = tableView.dequeueReusableCell(withIdentifier: "cellID", for: indexPath) as! PageCell
// set more stuff here
}
... // more code
}
My issue is that I am trying to get a box showing where the ImageView is that the user can click on to load in a picture. I am unsure how to do that and place all the relevant buttons as well (Trash, X, etc.)
Any help would be greatly appreciated.
EDIT
Okay, I was trying to follow this tutorial and I can't quite get it to work. In my prototype cell, I see this:
But the result is this:
I made the UIImageView have a background so I can see it. I have two constraints for the UIImageView which are: width = 240, height = 128 and two constraints for the Page Label which are: width = 240, height = 21. Two questions: why are my elements not placed correctly even though I have it correctly placed in the Storyboard? And why is the cell height not dynamically resizing to accommodate the elements?
I have these two lines in my viewDidLoad method of the TakePhotosVC but it doesn't seem to do anything.
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 200
If it's relevant, I get this warning when I run the Simulator.
Warning once only: Detected a case where constraints ambiguously
suggest a height of zero for a tableview cell's content view. We're
considering the collapse unintentional and using standard height
instead.
EDIT 2
I got it to work. For any poor souls reading this after me, you have to click on those dotted pink lines in the Constraints window editor and then click "Add X Constraints" in order to get the ImageView to center and stuff.
My issue is that I am trying to get a box showing where the ImageView
is that the user can click on to load in a picture. I am unsure how to
do that and place all the relevant buttons as well (Trash, X, etc.)
I am not sure if I understand you correctly. You have a cell with an UIImageView. But you want to show a box to visually indicate where the user should touch to add an UIImage (?)
Why not simply add a UIButton on top of the UIImageView with the exact same frame size, and on touch, you fire your action to add the image, and once the image is successfully added, you can set the UIButton to hidden.
If the user deletes the image with the trash button, you simply show the UIButton again by hidden = NO.
Other solution:
Add a border to the UIImageView with custom colors and add a UITapGestureRecognizer to fire an action. (Make sure you set the UIImageView to userInteractionEnabled = YES;
You can allso add a Placeholder image to the UIImageView when there is no image set, with your custom design.
The easiest approach would be to use a xib instead of placing the buttons programmatically. To do this, add a new file and select xib. In a xib, you can pre-make a tableviewcell with the image view, and you buttons placed for you already with constraints. Then, you can subclass this table view cell and connect the image view and buttons with ib outlets and ib actions to access the buttons and image view. Then, in your cellForRow function, load the xib like this:
Bundle.main.loadNibNamed("NameOfNib", owner: self, options: nil).first as! NameOfSubclass
I would advise to read more on xibs and nibs.
I have set a background image for my UITableViewController and then added a blur effect with the following code:
var blur = UIBlurEffect(style: UIBlurEffectStyle.Dark)
var blurView = UIVisualEffectView(effect: blur)
blurView.frame = self.view.bounds
self.view.insertSubview(blurView, atIndex: 0)
When I scroll down, the background image is still there but the blur effect is only there for the first few cells that fit into the view at a time. How can I make it so the blur effect is there as I scroll?
I tried adding the blur effect to each cell, but that makes it look really weird.
For UITableViewControllers self.view is the UITableView it self. That means any subview you add to self.view will scroll along with the content of the table view.
You could either make an own UIViewController, set up UITableView manually and place it in front of the blur view (instead of placing the blur view inside the table view) or you could move the blur view's location when the table view is scrolled.
To move the blur view to compensate for the table view's offset you can do something like this:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
var blurViewFrame = CGRect()
blurViewFrame.size = view.bounds.size
blurViewFrame.y = tableView.contentOffset.y
blurView.frame = blurViewFrame
}
I was able to add a gradient my UITableView, but I have the issue of when I have to scroll through my cells, the gradient background scrolls along also. I want the background to stay consistent as I scroll up or down. How can I achieve this? Do I have to create a custom UITableView in order to do this?
The pictures below show what it currently looks like.
Here is my code for adding the gradient to the UITableView:
func addGradientToBackground(){
var gradient : CAGradientLayer = CAGradientLayer()
gradient.frame = self.tableView.bounds
gradient.colors = [UIColor.blueColor().CGColor, UIColor.redColor().CGColor]
self.tableView.layer.insertSublayer(gradient, atIndex: 0)
}
Messing around will setting the gradient doesn't work either, like setting:
self.view.layer.insertSublayer(gradient, atIndex: 0)
or changing the bounds:
gradient.frame = self.tableView.frame
Also, in cellForRowAtIndexPath I set the UITableViewCells background color to clear:
cell.backgroundColor = UIColor.clearColor()
I can't add images, but here is the link if you wish to see them: http://imgur.com/Vtka1tO,6faLMkr#0
The gradient needs to be behind the table view if you don't want it to scroll. If you're using a UITableViewController, the only thing behind is the window, so you could give it the gradient, and make the cells and the table view have a clear background color. If you're using a UIViewController with a table view as a subview, then you could give the controller's main view a gradient background color.
Have you thought to add a background image as follows?
var imageView = UIImageView(frame: CGRectMake(10, 10, cell.frame.width - 10, cell.frame.height - 10))
let image = UIImage(named: ImageNames[indexPath.row])
imageView.image = image
cell.backgroundView = UIView()
cell.backgroundView.addSubview(imageView)