I have a tableView having 30 rows and I also have a View on the top of tableView(Not in the tableview header) ,I want to capture the complete screen shot of the screen including the View and all the row of tableview but i can only able to capture the visible rows of tableview and the view .Please help me and thanks in advance.
Here is my Code and the screen shot of simulator.
Note(I don't want my View to be in tableview header because it will also scroll when we scroll the tableview thats why the view is fixed)
- (void)viewDidLoad {
[super viewDidLoad];
_myTableView.delegate = self;
_myTableView.dataSource = self;
UIBarButtonItem *next = [[UIBarButtonItem alloc]initWithTitle:#"Next" style:UIBarButtonItemStylePlain target:self action:#selector(nextButtonAction)];
UIBarButtonItem *screenShot = [[UIBarButtonItem alloc]initWithTitle:#"Screenshot" style:UIBarButtonItemStylePlain target:self action:#selector(screenshotButtonAction)];
self.navigationItem.leftBarButtonItem = screenShot;
self.navigationItem.rightBarButtonItem = next;
}
-(void)nextButtonAction
{
NextViewController *myVc = [[UIStoryboard storyboardWithName:#"Main" bundle:nil]instantiateViewControllerWithIdentifier:#"NextViewController"];
NSLog(#"value of image is %#",viewImage);
myVc.myImage = viewImage;
[self.navigationController pushViewController:myVc animated:YES];
}
-(void)screenshotButtonAction
{
UIView *viewToRender = self.myTableView;
CGPoint contentOffset = self.myTableView.contentOffset;
UIGraphicsBeginImageContext(viewToRender.bounds.size);
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextTranslateCTM(ctx, 0,-contentOffset.y ); //-contentOffset.y
[viewToRender.layer renderInContext:ctx];
viewImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 30;
}
- (UITableViewCell )tableView:(UITableView )tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *myString = #"reused";
UITableViewCell *Cell = [tableView dequeueReusableCellWithIdentifier:myString];
if (Cell == nil)
{
Cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:myString];
}
Cell.textLabel.text = [NSString stringWithFormat:#"This is Cell %ld",indexPath.row];
return Cell;
}
I've changed this code for Swift 3 from Getting a screenshot of a UIScrollView, including offscreen parts
Edit: 2022 - TableView get restored after screenshot
func screenshot() -> UIImage{
var image = UIImage();
UIGraphicsBeginImageContextWithOptions(self.tableView.contentSize, false, UIScreen.main.scale)
// save initial values
let savedContentOffset = self.tableView.contentOffset;
let savedFrame = self.tableView.frame;
let savedBackgroundColor = self.tableView.backgroundColor
// reset offset to top left point
self.tableView.contentOffset = CGPoint(x: 0, y: 0);
// set frame to content size
self.tableView.frame = CGRect(x: 0, y: 0, width: self.tableView.contentSize.width, height: self.tableView.contentSize.height);
// remove background
self.tableView.backgroundColor = self.tableView.backgroundColor;
// make temp view with scroll view content size
// a workaround for issue when image on ipad was drawn incorrectly
let tempView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.contentSize.width, height: self.tableView.contentSize.height));
// save superview
let tempSuperView = self.tableView.superview
// Save constraints
guard let superView = self.tableView.superview else {
return UIImage();
}
//get old constraints from table
var oldConstraints: [NSLayoutConstraint] = []
for constraint in superView.constraints {
if constraint.firstItem as? NSObject == self.tableView || constraint.secondItem as? NSObject == self.tableView{
oldConstraints.append(constraint)
}
}
// remove scrollView from old superview
self.tableView.removeFromSuperview()
// and add to tempView
tempView.addSubview(self.tableView)
// render view
// drawViewHierarchyInRect not working correctly
tempView.layer.render(in: UIGraphicsGetCurrentContext()!)
// and get image
image = UIGraphicsGetImageFromCurrentImageContext()!;
// and return everything back
tempView.subviews[0].removeFromSuperview()
tempSuperView?.addSubview(self.tableView)
//activate table's old constraints
NSLayoutConstraint.activate(oldConstraints)
// restore saved settings
self.tableView.contentOffset = savedContentOffset;
self.tableView.frame = savedFrame;
self.tableView.backgroundColor = savedBackgroundColor
UIGraphicsEndImageContext();
return image
}
Related
Thanks to gleb vodovozov's idea , I can capture the image of entire my TableView including offscreen parts but the superview doesn't restore my TableView as its "before changes" position after using it to render image in a tempView.
I've checked his code carefully and I didn't see any issues. Maybe just because of iOS 13 "changes" so the code that works with previous iOS versions is malfunctioning now?
Below is his code
Any help is strongly appreciated!
var image = UIImage()
UIGraphicsBeginImageContextWithOptions(self.myTable.contentSize, false, UIScreen.main.scale)
// save initial values
let savedContentOffset = self.myTable.contentOffset
let savedFrame = self.myTable.frame
let savedBackgroundColor = self.myTable.backgroundColor
// reset offset to top left point
self.myTable.contentOffset = CGPoint(x: 0, y: 0)
// set frame to content size
self.myTable.frame = CGRect(x: 0, y: 0, width: self.myTable.contentSize.width, height: self.myTable.contentSize.height)
// remove background
self.myTable.backgroundColor = UIColor.clear
// make temp view with scroll view content size
// a workaround for issue when image on ipad was drawn incorrectly
let tempView = UIView(frame: CGRect(x: 0, y: 0, width: self.myTable.contentSize.width, height: self.myTable.contentSize.height))
// save superview
let tempSuperView = self.myTable.superview
// remove scrollView from old superview
self.myTable.removeFromSuperview()
// and add to tempView
tempView.addSubview(self.myTable)
// render view
// drawViewHierarchyInRect not working correctly
tempView.layer.render(in: UIGraphicsGetCurrentContext()!)
// and get image
image = UIGraphicsGetImageFromCurrentImageContext()!
// and return everything back
tempView.subviews[0].removeFromSuperview()
tempSuperView?.addSubview(self.myTable)
// restore saved settings
self.myTable.contentOffset = savedContentOffset
self.myTable.frame = savedFrame
self.myTable.backgroundColor = savedBackgroundColor
UIGraphicsEndImageContext()
return image
// remove scrollView from old superview
self.myTable.removeFromSuperview()
From documentation:
func removeFromSuperview(): Calling this method removes any constraints that refer to the view you are removing, or that refer to any view in the subtree of the view you are removing.
I know that you restore the frame, but you may need to save constraints in array before removing it from super view, then add them again after adding it again to super view.
// Save constraints
guard let superView = myTable.superView else {
return
}
var oldConstraints: [NSLayoutConstraint] = []
for constraint in superView.constraints {
if constraint.firstItem == myTable || constraint.secondItem == myTable {
oldConstraints.append(constraint)
}
}
self.myTable.removeFromSuperview()
// ...
tempSuperView?.addSubview(self.myTable)
// Restore old constraints
NSLayoutConstraint.activate(oldConstraints)
I've added tableview's old constraints to this function.
func screenshot() -> UIImage{
var image = UIImage();
UIGraphicsBeginImageContextWithOptions(self.tableView.contentSize, false, UIScreen.main.scale)
// save initial values
let savedContentOffset = self.tableView.contentOffset;
let savedFrame = self.tableView.frame;
let savedBackgroundColor = self.tableView.backgroundColor
// reset offset to top left point
self.tableView.contentOffset = CGPoint(x: 0, y: 0);
// set frame to content size
self.tableView.frame = CGRect(x: 0, y: 0, width: self.tableView.contentSize.width, height: self.tableView.contentSize.height);
// remove background
self.tableView.backgroundColor = self.tableView.backgroundColor;
// make temp view with scroll view content size
// a workaround for issue when image on ipad was drawn incorrectly
let tempView = UIView(frame: CGRect(x: 0, y: 0, width: self.tableView.contentSize.width, height: self.tableView.contentSize.height));
// save superview
let tempSuperView = self.tableView.superview
// Save constraints
guard let superView = self.tableView.superview else {
return UIImage();
}
//get old constraints from table
var oldConstraints: [NSLayoutConstraint] = []
for constraint in superView.constraints {
if constraint.firstItem as? NSObject == self.tableView || constraint.secondItem as? NSObject == self.tableView{
oldConstraints.append(constraint)
}
}
// remove scrollView from old superview
self.tableView.removeFromSuperview()
// and add to tempView
tempView.addSubview(self.tableView)
// render view
// drawViewHierarchyInRect not working correctly
tempView.layer.render(in: UIGraphicsGetCurrentContext()!)
// and get image
image = UIGraphicsGetImageFromCurrentImageContext()!;
// and return everything back
tempView.subviews[0].removeFromSuperview()
tempSuperView?.addSubview(self.tableView)
//activate table's old constraints
NSLayoutConstraint.activate(oldConstraints)
// restore saved settings
self.tableView.contentOffset = savedContentOffset;
self.tableView.frame = savedFrame;
self.tableView.backgroundColor = savedBackgroundColor
UIGraphicsEndImageContext();
return image
}
for subView in searchBar.subviews {
if let scopeBar = subView as? UISegmentedControl {
scopeBar.backgroundColor = UIColor.blueColor()
}
}
I've been trying the above code to attempt to get a reference to the scopeBar and subsequently set its background color, but I am not able to get a reference. It seems to only go through the loop once, implying that there is only a single subview for the search bar. In the debugger the search bar appears to have an instance variable called _scopeBar with a type of (UISegmentedControl *).
if let topView = searchBar.subviews.first {
for subView in topView.subviews {
if let cancelButton = subView as? UIButton {
cancelButton.tintColor = UIColor.whiteColor()
cancelButton.enabled = true
}
}
}
The second block of code works for accessing the cancelButton of the search bar.
You can set the scopeBar background image as a solid color image.
First, you will need to create an UIImage from a color. In order to do that, you can create a function, or an extension on the UIImage, such as the following code:
Swift 3
import UIKit
extension UIImage {
class func imageWithColor(color: UIColor) -> UIImage {
let rect: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContextWithOptions(CGSize(width: 1, height: 1), false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
After that, you can simply set the backgroundImage on the scope bar:
Swift 3
// Set the scopeBar's background color:
searchBar.scopeBarBackgroundImage = UIImage.imageWithColor(color: UIColor.blue)
I have a sample issue, and I solved this as below code.
CGSize imageSize = CGSizeMake(64, 64);
UIColor *fillColor = [UIColor colorWithRed:228/255.0 green:228/255.0 blue:228/255.0 alpha:1.0];
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[fillColor setFill];
CGContextFillRect(context, CGRectMake(0, 0, imageSize.width, imageSize.height));
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.searchController.searchBar.scopeBarBackgroundImage = image;
- (void)changeScopeBarColor {
NSMutableArray<UIView*> *views = [NSMutableArray new];
NSArray<UIView *> *subviews = [_searchBar subviews];
[views addObjectsFromArray:subviews];
for (;;) {
if (views.count == 0) {
break;
}
UIView *v = [views firstObject];
[views removeObject:v];
if ([[[v class] description] isEqualToString:#"_UISearchBarScopeBarBackground"]) {
v.backgroundColor = [UIColor whiteColor];
break;
}
if (v.subviews.count > 0)
[views addObjectsFromArray:v.subviews];
}
}
My code works for the most part.
The issue I am having is the images start out as square, and change to circle when I scroll the table or refresh it.
What am I missing?
Here's my code:
cell.imageView.layer.cornerRadius = cell.imageView.frame.size.width / 2.0;
cell.imageView.layer.borderWidth = 3.0;
cell.imageView.layer.borderColor = [UIColor colorWithRed:157.0/255.0 green:34.0/255.0 blue:53.0/255.0 alpha:1.0]
.CGColor;
cell.imageView.clipsToBounds = YES;
NSDictionary *tweet = (self.results)[indexPath.row];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSString * imageString = [tweet valueForKeyPath:#"user.profile_image_url"];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:imageString]];
if (imageData != nil)
{
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData: imageData];
[cell setNeedsLayout];
});
}
});
EDIT ---- The code is in cellForRowAtIndexPath
Right when I launch the app the cell images are square. If I pullToRefresh the change to round or if I start scrolling the table they change to round.
EDIT TWO
Another issue I am seeing is the images change as I scroll.
How do I prevent this?
In order if anyone having this problem, here is the solution in
Swift
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:ContactCellTableViewCell? = tableView.dequeueReusableCellWithIdentifier("contactCell", forIndexPath: indexPath) as? ContactCellTableViewCell
var contact : ContactStruct
image = searchResults[indexPath.row]
let newImage = resizeImage(image, toTheSize: CGSizeMake(70, 70))
var cellImageLayer: CALayer? = cell?.imageView.layer
cellImageLayer!.cornerRadius = 35
cellImageLayer!.masksToBounds = true
cell?.imageView.image = newImage
return cell!
}
As you might noticed the 35 hardcode is basically half of the image size which is 70 in here.
And here is the resize function:
func resizeImage(image:UIImage, toTheSize size:CGSize)->UIImage{
var scale = CGFloat(max(size.width/image.size.width,
size.height/image.size.height))
var width:CGFloat = image.size.width * scale
var height:CGFloat = image.size.height * scale;
var rr:CGRect = CGRectMake( 0, 0, width, height);
UIGraphicsBeginImageContextWithOptions(size, false, 0);
image.drawInRect(rr)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext();
return newImage
}
Note: I am using a custom cell class as below:
import UIKit
class ContactCellTableViewCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var contactImage: UIImageView!
#IBOutlet weak var phoneLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
It really took me a while to figure this one out. The images become rounded after scrolling at first, but now using this code you are going to have the rounded images inside the cell from beginning.
Hope it helped anyone.
Try this in override-
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
// image Width(84) / 2 = 42
cell.CellImage.layer.cornerRadius = 42.0
cell.CellImage.layer.masksToBounds = true
//or
cell.CellImage.layer.cornerRadius = cell.CellImage.frame.width / 2
cell.CellImage.clipsToBounds = true
}
Most likely the cell's frame (and hence the imageView's frame) isn't set the very first time the cell is created. So setting the imageView's layer's cornerRadius based on that initial frame doesn't work. The best solution is to implement the tableView:willDisplayCell:forRowAtIndexPath: delegate method and set the layer there:
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
cell.imageView.layer.cornerRadius = cell.imageView.frame.size.width / 2.0;
}
Its simple..
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.ImageView.layer.cornerRadius = 150.0f;
cell.ImageView.layer.borderWidth = 2.0f;
cell.ImageView.layer.borderColor = [UIColor blackColor].CGColor;
cell.ImageView.clipsToBounds = YES;
}
Refer this link for more information: http://ios-blog.co.uk/tutorials/quick-tips/how-to-create-rounded-avatars-in-your-ios-application/
Create a custom cell, and add an image view (with an IBOutlet), sized and positioned however you want (the outlet is "iv" in my example below). Put the code to make image view round in the awakeFromNib method (assuming your cell is created in a nib or storyboard).
-(void)awakeFromNib {
self.iv.layer.cornerRadius = self.iv.frame.size.width / 2.0;
self.iv.layer.borderWidth = 3.0;
self.iv.layer.borderColor = [UIColor colorWithRed:157.0/255.0 green:34.0/255.0 blue:53.0/255.0 alpha:1.0].CGColor;
self.iv.clipsToBounds = YES;
}
I had a similar issue, my UIImageView was initially a square and would only show as circular when the UITableViewCell it was within was either highlighted or selected.
It was a simple fix:
Swift 2.0
imgView.layer.cornerRadius = imgView.frame.width / 2
imgView.clipsToBounds = true
This was placed inside the awakeFromNib() for my custom UITableViewCell.
This is assuming imgView is the name of the UIImageView hooked up via storyboard inside this custom UITableViewCell.
#interface MyCell : UITableViewCell
#end
#implementation MyCell
- (void)awakeFromNib
{
[super awakeFromNib];
self.imageView.layer.masksToBounds = YES;
self.textLabel.font = [UIFont systemFontOfSize:17];
self.textLabel.textColor = [UIColor darkTextColor];
}
// --- image view frame is empty rect inside tableView: willDisplayCell:
// +++ set cornerRadius inside layoutSubviews works.
- (void)layoutSubviews
{
[super layoutSubviews];
// layout image view
CGRect vfr = self.frame;
CGRect imgvr = self.imageView.frame;
imgvr.origin.x = 16;
imgvr.size.width = CGRectGetHeight(vfr);
self.imageView.frame = imgvr;
// update corner radius
self.imageView.layer.cornerRadius = imgvr.size.width * 0.5f;
// layout label
CGRect lblr = self.textLabel.frame;
lblr.origin.x = CGRectGetMaxX(imgvr) + 16;
lblr.size.width = CGRectGetWidth(vfr) - CGRectGetMaxX(imgvr) - 32;
self.textLabel.frame = lblr;
}
#end
In case your cell is by code:
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let myImageView = (cell as! MyCustomCell).myImageView
myImageView.layoutIfNeeded()
myImageView.layer.cornerRadius = myImageView.frame.width / 2.0
}
cell.imageView?.layer.cornerRadius = 22.0
cell.imageView?.layer.masksToBounds = true
Set the image view to a circle inside the async call where you set the image.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSString * imageString = [tweet valueForKeyPath:#"user.profile_image_url"];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:imageString]];
if (imageData != nil)
{
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = [UIImage imageWithData: imageData];
cell.imageView.layer.cornerRadius = cell.imageView.frame.size.width / 2.0;
cell.imageView.layer.borderWidth = 3.0;
cell.imageView.layer.borderColor = [UIColor colorWithRed:157.0/255.0 green:34.0/255.0 blue:53.0/255.0 alpha:1.0]
.CGColor;
cell.imageView.clipsToBounds = YES;
[cell setNeedsLayout];
});
}
});
Here is a perfect and state away solution for circular image in UITableview Cell.
Simply modify your UITableviewCell (custom cell) class with below code.
override func awakeFromNib() {
super.awakeFromNib()
imgEvent.layer.frame = (imgEvent.layer.frame).insetBy(dx: 0, dy: 0)
imgEvent.layer.borderColor = UIColor.gray.cgColor
imgEvent.layer.cornerRadius = (imgEvent.frame.height)/2
imgEvent.layer.masksToBounds = false
imgEvent.clipsToBounds = true
imgEvent.layer.borderWidth = 0.5
imgEvent.contentMode = UIViewContentMode.scaleAspectFill
}
It will also helps to solve the problem of image circular only after scrolling table..(if any)
I have UITableView. I want to add a UITextField above tableView, which could be accessible by pulling tableView down. And I want to hide my textField by pulling tableView up. How can I do this?
Here's what I tried:
[self.messagesTableView addSubview:self.messageField];
- (UITextField*)messageField
{
if (!_messageField)
{
_messageField = [[UITextField alloc] initWithFrame:CGRectMake(0, 0, self.messagesTableView.frame.size.width, kMessageFieldHeight)];
_messageField.autoresizingMask = UIViewAutoresizingFlexibleWidth;
_messageField.backgroundColor = [UIColor greenColor];
}
return _messageField;
}
- (void)scrollViewDidScroll:(UIScrollView*)scrollView
{
if (scrollView == self.messagesTableView)
{
CGRect newFrame = self.messagesTableView.frame;
newFrame.origin.y = self.messagesTableView.contentOffset.y + kMessageFieldHeight;
self.messagesTableView.frame = newFrame;
}
}
I have done such kind of functionality in my application. What i did just follow the steps.
1) Add one view to negative position of tableView. Here in this view you can add your textField or button whatever you want as per your requirement.
UIView *viewForSearchBar = [[UIView alloc]initWithFrame:CGRectMake(0, -50, 320, 50)];
viewForSearchBar.backgroundColor = [UIColor clearColor];
[self._tableView addSubview:viewForSearchBar];
self._tableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
2) now when user starts dragging tableview (actual scrollview of table view) you can call scrollview's delegate methods according it to test it.
When you dragging/scrolling tableView down then you will get contentOffset.y will be less then 0, I have explain here in code.
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate{
if (decelerate) {
[txtSearch resignFirstResponder];
}
id<UILayoutSupport> topLayoutGuide = self.topLayoutGuide;
if(scrollView.contentOffset.y < 0)
{
UIView* hiddenHeader = ...; // this points to the hidden header view above
CGRect headerFrame = [hiddenHeader frame];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
self._tableView.contentInset = UIEdgeInsetsMake(headerFrame.size.height + [topLayoutGuide length], 0, 0, 0);
[UIView commitAnimations];
} else {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.2];
self._tableView.contentInset = UIEdgeInsetsMake([topLayoutGuide length], 0, 0, 0);
[UIView commitAnimations];
}
}
This two steps are working fine for me, as i have implemented. Let me add images to verify it.
if you still have any queries you can ask me.
Swift 2.0:
I worked out Nirav's answer in swift Xcode 7.1. Have a look.
let footerView = UIView()
let scroll = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
var searchBar:UISearchBar?
searchBar = UISearchBar(frame: CGRectMake(0, 0, 320, 44))
searchBar!.delegate = self
searchBar!.tintColor = UIColor.orangeColor()
footerView.addSubview(searchBar!)
footerView.frame = CGRectMake(0, -50, 320, 50)
footerView.backgroundColor = UIColor.clearColor()
self.listWrapTableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0);
self.listWrapTableView.addSubview(footerView)
}
Adding scroll method using UIScrollViewDelegate.
func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {
if(scrollView.contentOffset.y < 0){
print("greater than table height")
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.2)
self.listWrapTableView.contentInset = UIEdgeInsetsMake(50, 0, 0, 0)
UIView.commitAnimations()
}
else
{
UIView.beginAnimations(nil, context: nil)
UIView.setAnimationDuration(0.2)
self.listWrapTableView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0)
UIView.commitAnimations()
}
}
Use UISearchBar instead of UITextField.
And add it as tableView's headerView
Eg:
UISearchBar *mySearchBar = [[UISearchBar alloc] init];
myTableIvew.tableHeaderView = mySearchBar;
I have a view for the iPhone that is basically split in two, with an informational display in the top half, and a UITableView for selecting actions in the bottom half. The problem is that there is no border or separator above the first cell in the UITableView, so the first item in the list looks funny. How can I add an extra separator at the top of the table, to separate it from the display area above it?
Here's the code to build the cells - it's pretty straightforward. The overall layout is handled in a xib.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
switch(indexPath.row) {
case 0: {
cell.textLabel.text = #"Action 1";
break;
}
case 1: {
cell.textLabel.text = #"Action 2";
break;
}
// etc.......
}
return cell;
}
To replicate the standard iOS separator lines, I use a 1 px (not 1 pt) hair line tableHeaderView with the table view's separatorColor:
// in -viewDidLoad
self.tableView.tableHeaderView = ({
UIView *line = [[UIView alloc]
initWithFrame:CGRectMake(0, 0,
self.tableView.frame.size.width, 1 / UIScreen.mainScreen.scale)];
line.backgroundColor = self.tableView.separatorColor;
line;
});
The same in Swift (thanks, Dane Jordan, Yuichi Kato, Tony Merritt):
let px = 1 / UIScreen.main.scale
let frame = CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: px)
let line = UIView(frame: frame)
self.tableView.tableHeaderView = line
line.backgroundColor = self.tableView.separatorColor
I just got hit with this same problem and realised that the separator at the top is only displayed whilst scrolling the table.
What I then did was the following
In Interface Builder go to "Scroll View Size"
Set the Content Insets of Top to 1
Alternatively in code you could do
[tableView setContentInset:UIEdgeInsetsMake(1.0, 0.0, 0.0, 0.0)];
NOTE: This no longer works for iOS7 as the separators are no longer shown at all.
I had the same problem and could not find an answer. So I added a line to the bottom of my table header.
CGRect tableFrame = [[self view] bounds] ;
CGFloat headerHeight = 100;
UIView * headerView = [[UIView alloc] initWithFrame:CGRectMake(0,0,tableFrame.size.width, headerHeight)];
// Add stuff to my table header...
// Create separator
UIView *lineView = [[UIView alloc] initWithFrame:CGRectMake(0, headerHeight-1, tableFrame.size.width, 1)] ;
lineView.backgroundColor = [UIColor colorWithRed:224/255.0 green:224/255.0 blue:224/255.0 alpha:1.0];
[headerView addSubview:lineView];
self.tableView.tableHeaderView = headerView;
Swift 4
extension UITableView {
func addTableHeaderViewLine() {
self.tableHeaderView = {
let line = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width, height: 1 / UIScreen.main.scale))
line.backgroundColor = self.separatorColor
return line
}()
}
}
I made a UITableView extension that displays a native style separator on top of the UITableView, while the table gets scrolled.
Here's the code
fileprivate var _topSeparatorTag = 5432 // choose unused tag
extension UITableView {
fileprivate var _topSeparator: UIView? {
return superview?.subviews.filter { $0.tag == _topSeparatorTag }.first
}
override open var contentOffset: CGPoint {
didSet {
guard let topSeparator = _topSeparator else { return }
let shouldDisplaySeparator = contentOffset.y > 0
if shouldDisplaySeparator && topSeparator.alpha == 0 {
UIView.animate(withDuration: 0.15, animations: {
topSeparator.alpha = 1
})
} else if !shouldDisplaySeparator && topSeparator.alpha == 1 {
UIView.animate(withDuration: 0.25, animations: {
topSeparator.alpha = 0
})
}
}
}
// Adds a separator to the superview at the top of the table
// This needs the separator insets to be set on the tableView, not the cell itself
func showTopSeparatorWhenScrolled(_ enabled: Bool) {
if enabled {
if _topSeparator == nil {
let topSeparator = UIView()
topSeparator.backgroundColor = separatorColor?.withAlphaComponent(0.85) // because while scrolling, the other separators seem lighter
topSeparator.translatesAutoresizingMaskIntoConstraints = false
superview?.addSubview(topSeparator)
topSeparator.leftAnchor.constraint(equalTo: self.leftAnchor, constant: separatorInset.left).isActive = true
topSeparator.rightAnchor.constraint(equalTo: self.rightAnchor, constant: separatorInset.right).isActive = true
topSeparator.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
let onePixelInPoints = CGFloat(1) / UIScreen.main.scale
topSeparator.heightAnchor.constraint(equalToConstant: onePixelInPoints).isActive = true
topSeparator.tag = _topSeparatorTag
topSeparator.alpha = 0
superview?.setNeedsLayout()
}
} else {
_topSeparator?.removeFromSuperview()
}
}
func removeSeparatorsOfEmptyCells() {
tableFooterView = UIView(frame: .zero)
}
}
To enable it, simply call tableView.showTopSeparatorWhenScrolled(true) after you set your delegate for your UITableView
In complement of Ortwin's answer, if you need to add some margin to your top separator to fit the separator inset, you have to embedded your top separator in another view :
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 1 / UIScreen.mainScreen.scale)];
UIView *topSeparator = [[UIView alloc] initWithFrame:CGRectMake(self.tableView.separatorInset.left, 0, self.tableView.frame.size.width - self.tableView.separatorInset.left - self.tableView.separatorInset.right, 1 / UIScreen.mainScreen.scale)];
topSeparator.backgroundColor = self.tableView.separatorColor;
[headerView addSubview:topSeparator];
self.tableView.tableHeaderView = headerView;
Hope it helps.
I solved this by adding one extra line at the beginning of the table. Just have to set its height to 1, set its the text to empty, disable user interaction for it and in the whole code adjust the indexPath.row value.
Add a separator between header view and first row :-
In view for Header in section delegate method add a subview self.separator
//#property (nonatomic, strong) UIImageView *separator;
- (CGFloat)tableView:(UITableView *)tableView
heightForHeaderInSection:(NSInteger)section {
return 41;
}
- (UIView *)tableView:(UITableView *)tableView
viewForHeaderInSection:(NSInteger)section {
self.headerView = [[UIView alloc] init];
self.headerView.backgroundColor = [UIUtils colorForRGBColor:TIMESHEET_HEADERVIEW_COLOR];
self.separator = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"seperator.png"]];
self.separator.frame = CGRectMake(0,40,self.view.frame.size.width,1);
[self.headerView addSubview:self.separator];
return self.headerView;
}