Add a button that scrolls with a UITableView in Swift - ios

I am trying to make a UIButton (or tappable UIView) appear above a UITableView. That is easy. The hard part is making it scroll when the user scrolls down the table view.
I have tried using a UIScrollView like so:
private var scroll = UIScrollView();
private var table = UITableView();
override func viewDidLoad()
{
super.viewDidLoad()
scroll = UIScrollView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height));
table = UITableView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height));
table.register(ATableCell.self, forCellReuseIdentifier: "reuseIdentifier");
table.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0);
table.backgroundColor = UIColor.clear;
table.separatorInset = .zero;
table.layoutMargins = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10);
table.rowHeight = UITableViewAutomaticDimension;
// table.estimatedRowHeight = 100;
table.dataSource = self;
table.delegate = self;
scroll.addSubview(table);
self.view.addSubview(table);
}
The scrollbar space at the top can hold a button but will always be there. I want it to stay above the table view but be out of focus when the user scrolls down (like a web page or like the standard mail app in the iphone which does this with the search bar and a table view). Thanks.

You can use the following 2 approaches to add a button above your tableview:
1. Section Header:
Add a section header in your top most section of your tableview. Do not forget to change the UITableViewStyle to plain or else the section header will stick on top.
2. Table Header View:
Add a tableHeaderView and place anything you want here. It will scroll as you scroll the tableview.
Hope it helps.

You can detect scrolling of UITableView using delegate method, where you can set position of UIButton so it can move according to your UITableView scrolling.
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
if (scrollView == myTableView){
// Your code here.....
}
}

Related

How to get tableView content to scroll behind blur effect in swift iOS

I am trying to figure out how to have my tableView content scroll behind another view while having the table view bottom start point be above the other view. Basically trying to figure out how Apple does the same effect in there iMessage app where the tableView of a conversation start above the text field but scrolls behind it and has a blur effect.
Thanks in advance
Apple's iMessage text field blur
If I understood you correctly then you would want to do this:-
add tableView in whole screen
add a view of any height (lets say 128) with opacity < 100% or just add Visual Effect View of any height.(make sure your tableView is behind Blur view)
flip table vertically (upside down)
flip table cells too
add contentInset to table view equal to height of blur view so that when table loads the content doesn't load behind blur
add scrollIndicatorInsets again equal to height of blur view so your scroll bar doesn't scroll to top(bottom because inverted) of table.
Try yourself:
Design a tableView with cells > 20,
add Visual Effect View, give height = 128
& add this in your viewDidLoad() :
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
tableView.delegate = self
tableView.dataSource = self
tableView.contentInset = UIEdgeInsets(top: 128, left: 0, bottom: 0, right: 0) //top space of content from table = 128
tableView.transform = CGAffineTransform(scaleX: 1, y: -1) //invert table upside down
tableView.scrollIndicatorInsets = UIEdgeInsets(top: 128, left: 0, bottom: 0, right: 0) //top space of scrollBar from table = 128, top space will act as bottom space after inverting in this case
}
Do same to invert table cells:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! Cell
cell.contentView.transform = CGAffineTransform(scaleX: 1, y: -1) //invert cells too
return cell
}
This should achieve the iMessage like behaviour.

Expanding ScrollView with TableViewCells

I am trying to expand my view when tableViewCells are added to the tableview to scroll the whole view rather than the table, but my implementation of increasing the size of the tableView and the ScrollView isn't quite working, I'm not sure if it has something to do with the code or the constraints set. What sort of constraints would I have to set in story board to make this work?
This is what I've tried and it isn't expanding the scroll view:
#IBAction func addExercisePressed(_ sender: Any) {
test.append("nice")
tableView.isScrollEnabled = false
tableView.frame = CGRect(x: tableView.frame.origin.x, y: tableView.frame.origin.y, width: self.view.frame.size.width, height: CGFloat(tableView.visibleCells.count * 120))
scrollView.contentSize = CGSize(width: self.view.frame.size.width, height: tableView.frame.size.height)
tableView.reloadData()
}
tableView.visibleCells.count isn't the same as number of cells at some time , also you need to use auto-layout constraints by giving the table in IB a default height and hooking it as an IBOutlet then inside viewDidLayoutSubviews/viewDidAppear do
self.tableHeight.constant = numOcells * 120
self.view.layoutIfNeeded()

How to remove top space from Top of TableView?

In my View controller i have 1 tableview with different Data.
Top Blue colour is View & bottom Blue colour is TabBar.
in Home Screen there's top View & in Trending screen i Hide it by changing it's constraint to 0.
Home and 2. Trending
When i scroll tableview to see new posts & when i click on Trending View i load new data in TableView & scroll tableview to top with the code.
dispatch_async(dispatch_get_main_queue(), ^{
[self.tblVW setContentOffset:CGPointZero animated:NO];
[self.tblVW reloadData];
});
but it will not move to top of tableview.
There's a space at top & when i touch tableview it will scroll to top.
In a grouped tableview,If you want to remove the default header in the top area, try setting:
tableView.tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: 0.1))
Grouped TableView:
Before:
After:
I guess you are using grouped tableview. Kindly make
self.tblVW.tableHeaderView = [[UIView alloc]initWithFrame:CGRectMake(0,0,0,0.01f)];
Even set height of tableview section header as 0.01f.
YourTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
Set Above code.
You need to disable automaticallyAdjustsScrollViewInsets .
add this line ViewDidLoad
self.automaticallyAdjustsScrollViewInsets = false
Try this to scroll the table view to top
dispatch_async(dispatch_get_main_queue(), ^{
[self.tblVW.scrollToRowAtIndexPath(NSIndexPath(forRow: 0,inSection: 0), atScrollPosition: UITableViewScrollPosition.Top, animated: true)];
[self.tblVW reloadData];
});
instead of setting content offset.
This works for me, put this code inside the viewDidLoad() tableView.contentInset = UIEdgeInsets(top: -35, left: 0, bottom: 0, right: 0)
Example:
override func viewDidLoad() {
super.viewDidLoad()
self.setupTableView()
}
func setupTableViews() {
tableView.contentInset = UIEdgeInsets(top: -35, left: 0, bottom: 0, right: 0)
}

How to add a view on top of UITableView that scrolls together, but stick to top after scrolling

I have a UIView with height of 100 pixels that's on top of my UITableView. When I scroll up I want the UIView to scroll together with my UITableView as if it's part it. When 50 pixels of my UIView is hidden from scrolling up, I want to pin the UIView at the top while I continue scrolling up. How can this be achieved? I tried using changing my UIView's top NSLayoutConstraint constant equal to my tableview's content offset, but they don't scroll at the same speed.
First make sure your tableView is grouped:
self.tableView = UITableView(frame: CGRect(x: 0, y: (self.navigationController?.navigationBar.frame.maxY)!, width: self.view.bounds.size.width, height: (self.view.bounds.size.height - (self.navigationController?.navigationBar.frame.maxY)!)), style: .grouped)
self.tableView.delegate = self
self.tableView.dataSource = self
self.view.addSubview(self.tableView)
Then you need to add the UIView into the subview of your tableView:
self.myView = UIView()
self.myView.backgroundColor = UIColor.green
self.myView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 100)
self.tableView.addSubview(self.myView)
Add a header of height 100 for your tableView's first section so that your cells are at right place:
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 100
}
Then adjust the frame of your UIView when scrolling:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = scrollView.contentOffset.y
if(offset > 50){
self.myView.frame = CGRect(x: 0, y: offset - 50, width: self.view.bounds.size.width, height: 100)
}else{
self.myView.frame = CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: 100)
}
}
Demo:
If I understand you'r question correctly, You can do it by implementing table view scrollViewDidScroll: method like this
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
static CGFloat previousOffset;
CGRect rect = self.yourUIView.frame;
//NSLog you'r UIView position before putting any condition
// NSLog(#"Origin %f",rect.origin.y);
rect.origin.y += previousOffset - scrollView.contentOffset.y;
previousOffset = scrollView.contentOffset.y;
//assuming you'r UIView y position starts from 0
//Before setting the condition please make sure to run without any
//condition if not working
if(rect.origin.y>=-50 && rect.origin.y<=0){
self.yourUIView.frame = rect;
}
}
Hope it helps...
What you need is to implement the viewForHeader inSection method for your tableView (remember to make your ViewController implementing the tableviewDelegate protocol) and once you've got it you should set your tableViewStyle to UITableViewStylePlain
Share your code if you are interested in more help.
Source: UITableView with fixed section headers
I got the same problem with
navigationItem.largeTitleDisplayMode = .always
navigationBar.prefersLargeTitles = true
and
tableView.contentInset = UIEdgeInsets(top: 40, left: 0, bottom: 0, right: 0)
For me nothing from any above options can help but I realised that you can just call
tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: false)
in viewDidload() and problem gone! :)
Totally forgot about this method and spent too much time for this creepy behavior.
Good Luck!

Make UIView fill UIScrollview

I have a paging scrollview with two views, and the first one is to fill the UIScrollview and the second to stay in the middle. I don't know what's going wrong, but it wouldn't fill on iPhone6 but, it fits fine on iPhone5. Below is my code:
View Hierarchy
UIView
--StackView (Properties -- Axis(Vertical) Alignment(Fill) Distribution(Fill) Spacing(0))
--UIView (Fixed height. 60)
--UIView (Main Views Holder)
--ScrollView(Content Size: Screen Width * 2, Height: Height left between it margin to the MainView and BottomView) and I notice, that the scrollview keeps remaining size 433 on both iPhone5 and 6. And when I check my storyboard, that's the exact same height there
--UIView(Height: 102, Width: Screen Width)BottomView
#IBOutlet weak var scrollView: UIScrollView!
var rectanglePhot: UIView!
var squarePhoto: UIView!
override func viewDidLoad() {
super.viewDidLoad()
scrollView.contentSize = CGSize(width: self.view.frame.size.width * 2, height: scrollView.frame.size.height)
scrollView.autoresizingMask = .FlexibleWidth
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.backgroundColor = UIColor.greenColor()
iniiCameraView()
}
func iniiCameraView() {
rectanglePhot = UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height)) <-- This is the problematic one
//rectanglePhot = UIView()
let specifyY = self.scrollView.frame.size.height - self.view.frame.size.width
squarePhoto = UIView(frame: CGRect(x: self.view.frame.size.width, y: specifyY, width: self.view.frame.size.width, height: self.view.frame.size.width))
scrollView.addSubview(rectanglePhot)
scrollView.addSubview(squarePhoto)
rectanglePhot.backgroundColor = UIColor.blueColor()
squarePhoto.backgroundColor = UIColor.brownColor()
print("Rect Height ", rectanglePhot.frame.size.height)
print("Scroll Height ", scrollView.frame.size.height)
print("Specify Y ", specifyY)
}
And the image Image Added to Scrollview a index[0]
Add the code in viewdidappear. The autolayout will be applied after viewdidload
Replace
UIView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.scrollView.frame.size.height))
With :
UIView(frame: CGRect(x: 0, y: 0, width: self.scrollView.bounds.size.width, height: self.scrollView.bounds.size.height))
With this the UIView will take the exact size of you scrollview
if you don't want to use autolayout: add subviews in viewDidLoad, that is fine but you also need to adjust their frames in viewDidLayoutSubviews method of UIViewController since your scrollView will have a different frame after autolayout passes.
if you are ok with using autolayout: don't rely on scrollView for sizing your subviews, relate size of your subviews to the size of self.view

Resources