I want to resize the tableviewcell when SDWebImage download finished.
Where should I put [UITableViewCell setNeedsUpdateConstraints]?
Or just send notification to UIViewController and reload tableview data?
ViewController.m
#import "ViewController.h"
#import <Masonry/Masonry.h>
#import <SDWebImage/UIImageView+WebCache.h>
#define WEAKSELF typeof(self) __weak weakSelf = self;
#interface ViewController ()
<UITableViewDataSource, UITableViewDelegate> {
UITableView *myTableView;
}
#property (nonatomic, retain) NSArray *items;
#end
#implementation ViewController
- (UIRectEdge)edgesForExtendedLayout {
return UIRectEdgeNone;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadRows:)
name:#"ReloadRows"
object:nil];
NSMutableArray *array = [NSMutableArray array];
for (NSInteger i = 0; i < 30; i ++) {
CGFloat width = arc4random() % 100 + 20.0f;
CGFloat height = arc4random() % 100 + 20.0f;
CGSize size = CGSizeMake(width, height);
[array addObject:[NSValue valueWithCGSize:size]];
}
self.items = array;
myTableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
myTableView.dataSource = self;
myTableView.delegate = self;
myTableView.estimatedRowHeight = 60.0f;
myTableView.rowHeight = UITableViewAutomaticDimension;
[self.view addSubview:myTableView];
UIView *superview = self.view;
[myTableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.bottom.equalTo(superview);
}];
}
- (void)reloadRows:(NSNotification *)notification {
NSIndexPath *ip = notification.object;
if (ip) {
TestCell *cell = [myTableView cellForRowAtIndexPath:ip];
[cell setNeedsUpdateConstraints];
[myTableView reloadRowsAtIndexPaths:#[ip] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
#pragma mark - UITableViewDataSource, UITableViewDelegate
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellID = #"Contact_People_Cell";
TestCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
if (!cell) {
cell = [[TestCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
}
NSValue *value = [self.items objectAtIndex:indexPath.row];
cell.imageSize = [value CGSizeValue];
[cell refreshInterface];
return cell;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
}
#end
TestCell
#define SIZE_DEFAULT CGSizeMake(140.0f, 100.0f)
#interface TestCell () {
UIImageView *imv;
}
#end
#implementation TestCell
#synthesize imageSize;
#synthesize indexPath;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
[self setupView];
}
return self;
}
- (void)setupView {
imv = [[UIImageView alloc] initWithFrame:CGRectZero];
imv.backgroundColor = [UIColor darkGrayColor];
[self.contentView addSubview:imv];
self.translatesAutoresizingMaskIntoConstraints = NO;
UIView *superView = self.contentView;
[imv mas_makeConstraints:^(MASConstraintMaker *make) {
make.width.equalTo(#(SIZE_DEFAULT.width));
make.height.equalTo(#(SIZE_DEFAULT.height));
make.left.top.bottom.equalTo(superView).with.offset(10.0f);
}];
}
- (void)updateConstraints {
[super updateConstraints];
UIView *superView = self.contentView;
[imv mas_updateConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(superView).with.offset(10.0f);
make.bottom.equalTo(superView).with.offset(-10.0f);
make.width.equalTo(#(ceilf(self.imageSize.width)));
make.height.equalTo(#(ceilf(self.imageSize.height)));
}];
}
- (void)refreshInterface {
WEAKSELF
[imv sd_setImageWithURL:[NSURL URLWithString:#"http://www.baidu.com"]
placeholderImage:nil
options:SDWebImageProgressiveDownload
progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
imv.backgroundColor = [UIColor purpleColor];
dispatch_async(dispatch_get_main_queue(), ^{
CGFloat width = arc4random() % 100 + 140.0f;
CGFloat height = arc4random() % 100 + 140.0f;
CGSize size = CGSizeMake(width, height);
weakSelf.imageSize = size;
[weakSelf setNeedsUpdateConstraints];
// NSIndexPath *ip = [weakSelf.indexPath copy];
// [[NSNotificationCenter defaultCenter] postNotificationName:#"ReloadRows" object:ip];
});
}];
}
#end
Use self-sized cells. After load image, change height constraint of UIImage and call reloadRowsAtIndexPaths: method
implement tableView heightForRowAtIndexPath: method to change the cell height as per downloaded image height
Related
I am trying to create custom cell for UiCollectionView where I need to update each cell from background.
So I have created custom class for each cell named Cell_Obj and updating the cell content from the Cell_Obj itself using a timer.
The below code add an image on cell and increment a counter in each 2 second and display it on new cell label.
On each time when I add new cell using a button on a viewcotroller the cell updating but every cell getting the same value on the label. It suppose to have different counter value as each cell is different instance of Cell_Obj but the counter value and labelTxt(the cell number) has the same value when each time the timer triggered.
ViewController.h
#import <UIKit/UIKit.h>
#import "Cell_Obj.h"
#interface ViewController : UIViewController<UICollectionViewDataSource,UICollectionViewDelegate>
#property (weak, nonatomic) IBOutlet UICollectionView *collection;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController (){
NSMutableArray *GridArray;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.collection setDelegate:self];
[self.collection setDataSource:self];
// Do any additional setup after loading the view, typically from a nib.
GridArray = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return GridArray.count;
}
// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (Cell_Obj *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
Cell_Obj *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
// cell.label.text = #"123";
/*cell.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:#"AppIcon.png",indexPath.row]];*/
return cell;
}
- (void)addImage
{
Cell_Obj *cell = [[Cell_Obj alloc] init];
// cell.label.text = #"123";
//cell.label.text = [NSString stringWithFormat:#"%d",[dvrGridArray count]-1];
NSString * txt = [NSString stringWithFormat:#"%d",[GridArray count]];
[cell updateTextLabelName: txt];
[GridArray addObject:cell];
[_collection insertItemsAtIndexPaths:#[[NSIndexPath indexPathForItem:[GridArray count]-1 inSection:0]]];
/* NSMutableArray *arrayWithIndexPaths = [NSMutableArray array];
[arrayWithIndexPaths addObject:cell];
[self.collection insertItemsAtIndexPaths:arrayWithIndexPaths];*/
}
- (IBAction)addClicked:(id)sender {
[self addImage];
}
- (IBAction)changeImage:(id)sender {
// DVR_Obj *cell = [dvrGridArray objectAtIndex:0];
// [cell changeImage ];
// [_collection reloadData];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:1 inSection:0];
Cell_Obj *cell = [_collection cellForItemAtIndexPath:indexPath];
[cell changeImage ];
}
#pragma mark Collection view layout things
// Layout: Set cell size
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"SETTING SIZE FOR ITEM AT INDEX %d", indexPath.row);
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
CGSize mElementSize = CGSizeMake((screenWidth/4)-2, (screenHeight/4)-2);
return mElementSize;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
return 1.0;
}
// Layout: Set Edges
- (UIEdgeInsets)collectionView:
(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
// return UIEdgeInsetsMake(0,8,0,8); // top, left, bottom, right
return UIEdgeInsetsMake(1,1,1,1); // top, left, bottom, right
}
#end
Cell_Obj.h
#import <UIKit/UIKit.h>
#interface Cell_Obj : UICollectionViewCell
#property (weak, nonatomic) IBOutlet UIImageView *imageView;
#property (weak, nonatomic) IBOutlet UILabel *label;
- (void)changeImage;
- (void)updateTextLabelName:(NSString*)str;
#end
Cell_Obj.m
#import "Cell_Obj.h"
static NSString *labelTxt ;// = [[NSString alloc] init];
static int counter;
#implementation Cell_Obj{
}
+ (void)initialize {
if (self == [Cell_Obj class]) {
labelTxt = [[NSString alloc] init];
counter=0;
}
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
- (void)awakeFromNib {
_imageView.image = [UIImage imageNamed:#"flower1.png"];
_label.text = labelTxt;
[NSTimer scheduledTimerWithTimeInterval:2.0f
target:self
selector:#selector(updateImage)
userInfo:nil
repeats:YES];
}
- (void)updateImage
{
_imageView.image = [UIImage imageNamed:#"AppIcon.png"];
counter++;
NSString * txt = [NSString stringWithFormat:#"%#-%d",labelTxt,counter];
_label.text = txt;
}
- (void)updateTextLabelName :(NSString*)str
{
labelTxt = str;
}
#end
Your each cell is not new cell. Cell_Obj *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath]; this statement reuses your cell with identifier "Cell". To create new cell each time , don't pass indexPath, pass nil instead.
I'm working on an iOS app and I created an UIViewController where I put my components and it works fine .
Now I'm trying to create a Custom UIView and to put my WebView and my SearchController into . I spent a lot of time without success .
Here is my .m file and I hope some one can help me with :
#import "HomeViewController.h"
#define widthtScreen [UIScreen mainScreen].bounds.size.width
#define heightScreen [UIScreen mainScreen].bounds.size.height
#interface HomeViewController () <UISearchResultsUpdating,UISearchBarDelegate,UIBarPositioningDelegate,UITableViewDataSource,UITableViewDelegate,MapWebViewDelegate>
#property(strong,nonatomic) MapWebView *webView;
#property (nonatomic) UIButton *btnGeolocate;
#property (nonatomic, strong) UISearchController *searchController;
#end
#implementation HomeViewController{
NSMutableArray *placesList;
BOOL isSearching;
}
-(void)loadView
{
[super loadView];
self.webView = [[MapWebView alloc] initWithFrame:CGRectMake(0, -100, widthtScreen, heightScreen+100)];
self.webView.mapWebViewDelegate = self;
[self.view addSubview:self.webView];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.navigationItem.hidesBackButton = YES;
mainDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
placesList = [[NSMutableArray alloc] init];
[self initializeSearchController];
mainDelegate.webView = self.webView;
self.btnGeolocate = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width-75,550,60,60)];
self.btnGeolocate.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[self.btnGeolocate setBackgroundImage:[UIImage imageNamed:#"geo.png"]
forState:UIControlStateNormal];
[self.btnGeolocate addTarget:self action:#selector(btnGeolocatePressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.btnGeolocate];
mainDelegate.btnZoomIn = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width-80,620,30,30)];
mainDelegate.btnZoomIn.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[mainDelegate.btnZoomIn setBackgroundColor:[UIColor blackColor]];
[mainDelegate.btnZoomIn addTarget:self action:#selector(btnZoomInPressed:) forControlEvents:UIControlEventTouchUpInside];
mainDelegate.btnZoomIn.tag=1;
UIImage *btnImage = [UIImage imageNamed:#"plus.png"];
[mainDelegate.btnZoomIn setImage:btnImage forState:UIControlStateNormal];
[self.view addSubview:mainDelegate.btnZoomIn];
mainDelegate.btnZoomOut = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width-40,620,30,30)];
mainDelegate.btnZoomOut.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
[mainDelegate.btnZoomOut setBackgroundColor:[UIColor blackColor]];
[mainDelegate.btnZoomOut addTarget:self action:#selector(btnZoomOutPressed:) forControlEvents:UIControlEventTouchUpInside];
mainDelegate.btnZoomOut.tag=1;
UIImage *btnImage2 = [UIImage imageNamed:#"minus.png"];
[mainDelegate.btnZoomOut setImage:btnImage2 forState:UIControlStateNormal];
[self.view addSubview:mainDelegate.btnZoomOut];
}
- (BOOL)slideNavigationControllerShouldDisplayLeftMenu
{
return YES;
}
- (BOOL)slideNavigationControllerShouldDisplayRightMenu
{
return YES;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"number :%lu",(unsigned long)[placesList count]);
return [placesList count];
}
- (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];
}
SuggestResultObject *sro = [SuggestResultObject new];
sro = [placesList objectAtIndex:indexPath.row];
cell.textLabel.text = sro.textPlace;
return cell;
}
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar{
self.navigationItem.leftBarButtonItem = nil;
self.navigationItem.rightBarButtonItem =nil;
return true;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.navigationItem.leftBarButtonItem = mainDelegate.leftBarButtonItem;
self.navigationItem.rightBarButtonItem = mainDelegate.rightBarButtonItem;
SuggestResultObject *sro = [SuggestResultObject new];
sro = [placesList objectAtIndex:indexPath.row];
self.searchController.active = false;
NSString *function = [[NSString alloc] initWithFormat: #"MobileManager.getInstance().moveToLocation(\"%#\",\"%#\")", sro.latPlace,sro.lonPlace];
[_webView evaluateJavaScript:function completionHandler:nil];
}
- (void)jsRun:(NSString *) searchText {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *function = [[NSString alloc] initWithFormat: #"MobileManager.getInstance().setSuggest(\"%#\")", searchText];
[_webView evaluateJavaScript:function completionHandler:nil];
});
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
isSearching = YES;
}
- (void)initializeSearchController {
UITableViewController *searchResultsController = [[UITableViewController alloc] initWithStyle:UITableViewStylePlain];
searchResultsController.tableView.dataSource = self;
searchResultsController.tableView.delegate = self;
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.definesPresentationContext = YES;
self.searchController.hidesNavigationBarDuringPresentation = false;
self.searchController.accessibilityElementsHidden= true;
self.searchController.dimsBackgroundDuringPresentation = true;
self.searchController.searchBar.frame = CGRectMake(self.searchController.searchBar.frame.origin.x, self.searchController.searchBar.frame.origin.y, self.searchController.searchBar.frame.size.width, 44.0);
self.navigationItem.titleView = self.searchController.searchBar;
self.searchController.searchResultsUpdater = self;
self.searchController.searchBar.delegate = self;
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
self.navigationItem.leftBarButtonItem = mainDelegate.leftBarButtonItem;
self.navigationItem.rightBarButtonItem = mainDelegate.rightBarButtonItem;
NSLog(#"Cancel clicked");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[placesList removeAllObjects];
}
-(void)updateSearchResultsForSearchController:(UISearchController *)searchController {
[placesList removeAllObjects];
if([searchController.searchBar.text length] != 0) {
isSearching = YES;
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[self jsRun:searchController.searchBar.text];
}
else {
isSearching = NO;
[((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];
}
}
-(void) btnGeolocatePressed : (id) sender{
}
-(void) btnZoomInPressed : (id) sender{
[_webView evaluateJavaScript:#"MobileManager.getInstance().zoomIn();" completionHandler:nil];
}
-(void) btnZoomOutPressed : (id) sender{
[_webView evaluateJavaScript:#"MobileManager.getInstance().zoomOut();" completionHandler:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)searchResult:(NSArray*)dataArray{
SuggestResultObject *sro = [SuggestResultObject new];
sro.textPlace = [dataArray objectAtIndex:0];
sro.lonPlace = [dataArray objectAtIndex:1];
sro.latPlace = [dataArray objectAtIndex:2];
[placesList addObject:sro];
[((UITableViewController *)self.searchController.searchResultsController).tableView reloadData];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
#end
Screenshots (Not sure how to scale images on stackoverflow.. OSX takes images in Retina format and they're fairly large! Sorry in advance!):
http://i.imgur.com/15qxDpc.png
http://i.imgur.com/QHduP07.png
How it works? Create a UIView and two sub-views: UITableView and
UIWebView. Constrain them properly.
Create the UISearchController with a nil SearchResultsController
as the parameter to the init method.
This lets the search controller know that the results will be
displayed in the current controller/view.
Next we setup the delegates for the UISearchController and create
the function for filtering.
Now that we have the view created, we need a UIViewController to
test it. We can either add the search bar to the tableView header OR
to the NavigationController if there is one..
Below, I have chosen to add it to the UINavigationController and I
told the UISearchController to NOT HIDE the navigation bar on
presentation.
That way, the results are displayed in the current view without hiding
the navigation bar.
You can then use the webview which is hidden and offscreen to do
whatever javascript searches you are using it for..
However, a better idea would be to use JSContext to execute
Javascript instead of a UIWebView. The advantage of the UIWebView
is that you can parse HTML and modify DOM which the JSContext
doesn't allow.
Anyway..
Here is the code I wrote for a UIView that contains a
UISearchController and a UIWebView.. and then to add it to a
UIViewController that is embedded in a UINavigationController.
//
// SearchView.h
// StackOverflow
//
// Created by Brandon T on 2016-06-26.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
#class SearchView;
#protocol SearchViewDelegate <UISearchBarDelegate>
- (void)didSelectRowAtIndexPath:(SearchView *)searchView tableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath;
#end
#interface SearchView : UIView
#property (nonatomic, weak) id<SearchViewDelegate> delegate;
- (UISearchBar *)getSearchBar;
- (UIWebView *)getWebView;
#end
//
// SearchView.m
// StackOverflow
//
// Created by Brandon T on 2016-06-26.
// Copyright © 2016 XIO. All rights reserved.
//
#import "SearchView.h"
#define kTableViewCellIdentifier #"kTableViewCellIdentifier"
#interface SearchView() <UITableViewDelegate, UITableViewDataSource, UISearchResultsUpdating>
#property (nonatomic, strong) UIWebView *webView;
#property (nonatomic, strong) UISearchController *searchController;
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, strong) NSArray *dataSource;
#property (nonatomic, strong) NSArray *searchResults;
#end
#implementation SearchView
- (instancetype)init {
if (self = [super init]) {
[self setupData];
[self initControls];
[self themeControls];
[self registerCells];
[self doLayout];
}
return self;
}
- (UISearchBar *)getSearchBar {
return _searchController.searchBar;
}
- (UIWebView *)getWebView {
return _webView;
}
- (void)setDelegate:(id<SearchViewDelegate>)delegate {
_delegate = delegate;
_searchController.searchBar.delegate = delegate;
}
- (void)setupData {
//Begin fake data
_dataSource = #[#"Cat", #"Dog", #"Bird", #"Parrot", #"Rabbit", #"Racoon", #"Rat", #"Hamster", #"Pig", #"Cow"];
//End fake data
_searchResults = [_dataSource copy];
}
- (void)initControls {
_webView = [[UIWebView alloc] init];
_searchController = [[UISearchController alloc] initWithSearchResultsController:nil];
_tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
}
- (void)themeControls {
[_webView setHidden:YES];
[_tableView setDelegate:self];
[_tableView setDataSource:self];
_searchController.searchResultsUpdater = self;
_searchController.dimsBackgroundDuringPresentation = false;
_searchController.definesPresentationContext = true;
_searchController.hidesNavigationBarDuringPresentation = false;
}
- (void)registerCells {
[_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:kTableViewCellIdentifier];
}
- (void)doLayout {
[self addSubview:_webView];
[self addSubview:_tableView];
NSDictionary *views = #{#"webView":_webView, #"tableView": _tableView};
NSMutableArray *constraints = [[NSMutableArray alloc] init];
[constraints addObject:[NSString stringWithFormat:#"H:|-(%d)-[webView]-(%d)-|", 0, 0]];
[constraints addObject:[NSString stringWithFormat:#"H:|-(%d)-[tableView]-(%d)-|", 0, 0]];
[constraints addObject:[NSString stringWithFormat:#"V:|-(%d)-[webView(%d)]-(%d)-[tableView]-(%d)-|", -100, 100, 0, 0]];
for (NSString *constraint in constraints) {
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:constraint options:0 metrics:nil views:views]];
}
for (UIView *view in self.subviews) {
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _searchController.active && _searchController.searchBar.text.length > 0 ? [_searchResults count] : [_dataSource count];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return 50;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:kTableViewCellIdentifier forIndexPath:indexPath];
if (_searchController.active && _searchController.searchBar.text.length > 0) {
cell.textLabel.text = _searchResults[indexPath.row];
}
else {
cell.textLabel.text = _dataSource[indexPath.row];
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.delegate && [self.delegate respondsToSelector:#selector(didSelectRowAtIndexPath:tableView:indexPath:)]) {
[self.delegate didSelectRowAtIndexPath:self tableView:tableView indexPath:indexPath];
}
}
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
[self filterResults:searchController.searchBar.text scope:nil];
}
- (void)filterResults:(NSString *)searchText scope:(NSString *)scope {
_searchResults = [_dataSource filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id _Nonnull evaluatedObject, NSDictionary<NSString *,id> * _Nullable bindings) {
NSString *object = [evaluatedObject uppercaseString];
return [object rangeOfString:[searchText uppercaseString]].location != NSNotFound;
}]];
[_tableView reloadData];
}
#end
Then I tested it with the below UIViewController which is embedded in a UINavigationController..
//
// ViewController.m
// StackOverflow
//
// Created by Brandon T on 2016-06-26.
// Copyright © 2016 XIO. All rights reserved.
//
#import "ViewController.h"
#import "SearchView.h"
#interface ViewController ()<SearchViewDelegate>
#property (nonatomic, strong) SearchView *searchView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initControls];
[self themeControls];
[self doLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)initControls {
_searchView = [[SearchView alloc] init];
}
- (void)themeControls {
self.edgesForExtendedLayout = UIRectEdgeNone;
self.navigationItem.titleView = [_searchView getSearchBar];
[_searchView setDelegate:self];
}
- (void)doLayout {
[self.view addSubview:_searchView];
NSDictionary *views = #{#"searchView":_searchView};
NSMutableArray *constraints = [[NSMutableArray alloc] init];
[constraints addObject:[NSString stringWithFormat:#"H:|-%d-[searchView]-%d-|", 0, 0]];
[constraints addObject:[NSString stringWithFormat:#"V:|-%d-[searchView]-%d-|", 0, 0]];
for (NSString *constraint in constraints) {
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:constraint options:0 metrics:nil views:views]];
}
for (UIView *view in self.view.subviews) {
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
}
}
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
self.navigationItem.leftBarButtonItems = nil;
self.navigationItem.rightBarButtonItems = nil;
}
- (void)didSelectRowAtIndexPath:(SearchView *)searchView tableView:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath {
[[searchView getWebView] stringByEvaluatingJavaScriptFromString:#"SomeJavascriptHere"];
}
#end
When I click the UITableViewCell , It have selection effect (grey background in clicked cell),But didSelectRowAtIndexPath is not calling ,what happen?
EDIT
this is my code
tableView.h file
#interface PopCardView : MMPopupView <UITableViewDataSource, UITableViewDelegate>
#end
tableView.m file
#property (nonatomic, strong) NSMutableArray *tagsArray;
#property (nonatomic, strong) UIView *backView;
#property (nonatomic, strong) UITableView *tableView;
#property (nonatomic, assign) NSUInteger lastIndex;
#end
-(id)initWithTags:(NSMutableArray *)tags{
self = [super init];
if (self) {
self.backView = [[UIView alloc] init];
self.backView.backgroundColor = [UIColor whiteColor];
self.backView.layer.cornerRadius = 5;
self.backView.layer.masksToBounds = YES;
[self addSubview:self.backView];
[self.backView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.bottom.right.equalTo(self);
}];
_tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, 324, 300) style:UITableViewStylePlain];
_tableView.tableFooterView =[[UIView alloc] init];
[self.backView addSubview:_tableView];
[_tableView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.right.bottom.equalTo(self.backView).insets(UIEdgeInsetsMake(45,0, 45, 15));
make.size.mas_equalTo(CGSizeMake(324, 200));
}];
[_tableView registerClass:[PopCardTagViewCell class] forCellReuseIdentifier:#"cell"];
_tableView.allowsSelection = YES;
_tableView.allowsSelectionDuringEditing = YES;
[_tableView setUserInteractionEnabled:YES];
_tableView.dataSource = self;
_tableView.delegate = self;
}
return self;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[_tagsArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
PopCardData *data = (PopCardData *)obj;
data.selected = #"0";
if (idx == indexPath.row) {
data.selected = #"1";
}
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *identifer = #"cell";
PopCardTagViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:identifer];
if (!cell) {
cell = [[PopCardTagViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifer];
}
[self configureCell:cell forIndexPath:indexPath];
return cell;
}
-(void)configureCell:(PopCardTagViewCell *)cell forIndexPath:(NSIndexPath *)indexPath {
PopCardData *data = (PopCardData *)[_tagsArray objectAtIndex:indexPath.row];
//configure cell
[cell setUserInteractionEnabled:YES];
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _tagsArray.count;
}
EDIT2
this is my initialize code of PopCardView,it use swift
let pop = PopCardView(tags: self.m_model.getItmes())
pop.show()
The code you show does not set any delegate to the table view. Either this is the reason or you posted an incomplete code snippet.
self.tableView.delegate = self;
and add UITableViewDelegate to your interface like
#interface ClassName ()<UITableViewDelegate>
Make sure you don't have anything in the cell that can swallow the touch event. Things like buttons and textfields can cause this. Strip everything from your cell, test to see if it works, then add things back in slowly to find the culprit.
I have a UITableView for an Instagram feed. I have implemented UIRefreshControl for pull to refresh functionality.
After drag and release the refresh control, and while the spinner is going, I'm able to drag the tableview down without the app crashing. However, if I scroll the tableview upwards, the app crashes (maybe because of cell 2, 3 etc?)
Here's a video showing the problem: http://www.screenmailer.com/v/DukT4lt2aUGm8c5MLRlGMg/2586/3a23tXo7uXs.mp4
Why is this happening?
Code for the .m file:
#import "InstagramViewController.h"
#import "InstagramCell.h"
#import <InstagramKit/InstagramKit.h>
#import "UIImageView+AFNetworking.h"
#interface InstagramViewController ()
{
NSMutableArray *mediaArray;
}
#property (nonatomic, strong) InstagramPaginationInfo *currentPaginationInfo;
#end
#implementation InstagramViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
//mediaArray = [[NSMutableArray alloc] init];
}
return self;
}
- (void)viewDidLoad
{
mediaArray = [[NSMutableArray alloc] init];
[super viewDidLoad];
[self loadMedia];
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:#selector(reloadMedia) forControlEvents:UIControlEventValueChanged];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
-(void)reloadMedia
{
self.currentPaginationInfo = nil;
[mediaArray removeAllObjects];
[self loadMedia];
}
-(IBAction)loadMedia
{
// start network indicator
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
[[InstagramEngine sharedEngine] getMediaWithTagName:#"AUFsommer" count:10 maxId:self.currentPaginationInfo.nextMaxId withSuccess:^(NSArray *media, InstagramPaginationInfo *paginationInfo) {
if (paginationInfo)
{
self.currentPaginationInfo = paginationInfo;
}
[mediaArray addObjectsFromArray:media];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
[self reloadData];
} failure:^(NSError *error) {
NSLog(#"Search Media Failed");
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}];
}
-(void)reloadData
{
[self.refreshControl endRefreshing];
[self.tableView reloadData];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[UIView alloc] init];
headerView.backgroundColor = [UIColor colorWithWhite:1.0f alpha:0.9f];
InstagramMedia *media = mediaArray[section];
// create imageview for profile photo
AsyncImageView *profilePhoto = [[AsyncImageView alloc] initWithFrame:CGRectMake(8, 8, 32, 32)];
profilePhoto.layer.borderColor = [[UIColor colorWithRed:204.0/255.0f green:204.0/255.0f blue:204.0/255.0f alpha:1.0f] CGColor];
profilePhoto.layer.borderWidth = 1;
profilePhoto.layer.masksToBounds = YES;
profilePhoto.layer.cornerRadius = 16.0;
[profilePhoto loadImageFromURL:[media.user.profilePictureURL absoluteString]];
// uifont settings
UIFont *labelFont = [UIFont boldSystemFontOfSize:13.0];
// create label for username
UILabel *usernameLabel = [[UILabel alloc] initWithFrame:CGRectMake(48, 0, 210, 48)];
usernameLabel.text = media.user.username;
usernameLabel.font = labelFont;
usernameLabel.textColor = [UIColor colorWithRed:235.0/255.0 green:24.0/255.0 blue:22.0/255.0 alpha:1.0f];
// create label for timestamp
UILabel *timestampLabel = [[UILabel alloc] initWithFrame:CGRectMake(250, 0, 54, 48)];
timestampLabel.textAlignment = NSTextAlignmentRight;
timestampLabel.font = labelFont;
// timestampLabel.text = [self stringForDisplayFromDate:media.createdDate];
// add to view
[headerView addSubview:profilePhoto];
[headerView addSubview:usernameLabel];
[headerView addSubview:timestampLabel];
return headerView;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return mediaArray.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
InstagramCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[InstagramCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// clear photo
[cell.igPhoto setImage:nil];
if (mediaArray.count >= indexPath.section+1)
{
InstagramMedia *media = mediaArray[indexPath.section];
cell.title.text = media.caption.text;
[cell.igPhoto loadImageFromURL:[media.standardResolutionImageURL absoluteString]];
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
InstagramMedia *media = mediaArray[indexPath.section];
CGSize maximumLabelSize = CGSizeMake(304.0f, 20000.0f);
CGSize expectedLabelSize = [media.caption.text sizeWithFont:[UIFont systemFontOfSize:13.0f] constrainedToSize:maximumLabelSize lineBreakMode:NSLineBreakByWordWrapping];
return (320.0f + expectedLabelSize.height + 20.0f);
}
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
CGFloat currentOffset = scrollView.contentOffset.y;
CGFloat maximumOffset = scrollView.contentSize.height - scrollView.frame.size.height;
if (maximumOffset - currentOffset < 10.0)
{
[self loadMedia];
}
}
#end
The first thing you should do is to add an exception breakpoint in your project, so you will know why and where it crashes.
The reason why your app is crashing is that you try to read in an empty array. In the method reloadMedia, you do this :
self.currentPaginationInfo = nil;
[mediaArray removeAllObjects];
So at this point, your array is empty, but your UITableView is not aware of that. By scrolling before your data is reloaded, the methods cellForRowAtIndexPath will get called and try to access an index in your empty array.
To fix this, you can call [self.tableView reloadData]; after [mediaArray removeAllObjects];. This way, the UITableView will makes its call to know how many rows and sections it should have and will be aware there is no more rows and sections.
Or, if you want the old information to still be in your UITableView during the loading, just don't nil the currentPaginationInfo or empty mediaArray in reloadMedia,
I'm making some kind of Facebook timeline similar app when new posts are added at certain offset of UITableView. After adding new posts to dataSource I [self.tableView reloadData] and everything is fine except small lag and sometimes wrong offset (+/- 150 px sometime depending in which direction you are scrolling).
Code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PostCell";
PostCell *postCell = (PostCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
Post *post = self.displayPosts[indexPath.row];
[postCell setPost:post];
return postCell;
}
- (void)updatePosts
{
[[APIClient sharedInstance] downloadPostsForPage:_currentPage withSuccessionBlock:^(NSArray *posts) {
NSLog(#"Display new posts!");
[self.displayPosts addObjectsFromArray:posts];
[self.mainTableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
_isLoadingMore = NO;
} failureBlock:^(NSError *err) {
// handle error
[self handleError:err];
}];
}
Post Cell:
#interface PostCell ()
#property (weak, nonatomic) IBOutlet PostView *postView;
#property (nonatomic, strong) Post *post;
#end
#implementation PostCell
- (void)setPost:(Post *)newPost
{
self.postView.post = newPost;
}
PostView:
- (void)setPost:(Post *)newPost
{
if (_post != newPost) {
_post = newPost;
}
[self layoutSubviews];
[self refreshContent];
}
- (void)layoutSubviews
{
[super layoutSubviews];
// define title attributes
NSDictionary *attributes = #{
NSForegroundColorAttributeName : [UIColor blackColor],
NSFontAttributeName : [UIFont systemFontOfSize:20.0f]};
CGFloat boundingTitleWidth = self.bounds.size.width - LEFT_TITLE_OFFSET - RIGHT_TITLE_OFFSET;
CGRect titleRect = [_post.title boundingRectWithSize:CGSizeMake(boundingTitleWidth, CGFLOAT_MAX) options:(NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading) attributes:attributes context:nil];
if (self.titleLabel == nil) {
self.titleLabel = [[UILabel alloc] init];
[self addSubview:self.titleLabel];
}
[self.titleLabel setFrame:CGRectMake(LEFT_TITLE_OFFSET, TOP_TITLE_OFFSET, titleRect.size.width, titleRect.size.height)];
[self.titleLabel setNumberOfLines:0];
[self.titleLabel sizeToFit];
// Draw the quarter image.
CGFloat imageY = TOP_TITLE_OFFSET + titleRect.size.height + TOP_IMAGE_OFFSET;
CGPoint point = CGPointMake(LEFT_IMAGE_OFFSET, imageY);
CGSize imageSize = self.post.image.size;
if (self.imageView == nil) {
self.imageView = [[UIImageView alloc] init];
[self addSubview:self.imageView];
}
[self.imageView setFrame:CGRectMake(point.x, point.y, imageSize.width, imageSize.height)];
}
- (void)refreshContent
{
[self.titleLabel setText:_post.title];
[self.imageView setImage:self.post.image];
}
Any help?
Thanks.