UICollectionView is not scrolling to position - ios

I have a UICollectionView in a static UITableView. I'm trying to make the collectionView scroll to an indexPath in viewDidLoad. It's not scrolling to position on startup, when I select an indexPath it scrolls to that position. I made a clean project that produces the problem.
I thought the simplest way to do this was instead of making you to try and recreate the problem, I would just upload it. So here it is: Project with problem

There are only two small problems:
1.The selectedDate does not match with your dates array. Compare the two date in the following image:
2.You should update UI in viewDidAppear as #Omar Al-Shammary said.
The Solution:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay fromDate:[NSDate date]];
[self setSelectedDate:[calendar dateFromComponents:components]];
}

Related

Reset MinimumDate in iOS UIDatePicker

I have 2 UIDatePickers, one set in UIDatePickerModeDate and the other in UIDatePickerModeTime.
If the first one has its date set to today, then the second one must have a restriction such that the user cannot select a time that is before now. To do this I use the setMinimumDate function. However, if the user sets a date in the future, I need to reset the minimumDate property, meaning that there should be no minimumDate set on the picker.
I am able to achieve this by calling
[self.timePicker setMinimumDate:nil];
But this gives me an exception in the Xcode console output as below.
-[__NSCFCalendar components:fromDate:]: date cannot be nil
Future exception.
A few of these errors are going to be reported with this complaint, then further violations will simply be ignored.
How can I remove the minimumDate property of my timePicker after it has been set, without this exception being raised?
Thank you.
EDIT:
The reason I tried setting it to nil was because Apple's documentation says that the default value of the minimumDate property is nil (here).
Also, I did try to set the minimum date to the future date selected by the user, after making the time component zero. This causes the time to be selected as 12 AM in the picker which is acceptable. Now if the user selects today's date again, nothing happens when I set the minimumDate property, i.e. I cannot toggle the minimumDate using this. The code is as follows:
(void)setMinimumDateForTimePicker {
if([[NSCalendar currentCalendar] isDateInToday:self.datePicker.date]) {
NSLog(#"Min date for today");
[self.timePicker setMinimumDate:[self roundUpToNearestFifteenMinutes:[NSDate date]]];
} else {
// date is in the future so zero out time
NSLog(#"Min date for the future");
NSDateComponents* selectedDateWithZeroTime = [[NSCalendar currentCalendar] components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate:self.datePicker.date];
[self.timePicker setMinimumDate:[[NSCalendar currentCalendar] dateFromComponents:selectedDateWithZeroTime]];
}
[self updateStartTimeField:nil];
}
This is the code that worked finally for what I was trying to do.
- (void)setMinimumDateForTimePicker {
if([[NSCalendar currentCalendar] isDateInToday:self.datePicker.date]) {
[self.timePicker setMinimumDate:[self roundUpToNearestFifteenMinutes:[NSDate date]]];
} else {
[self.timePicker setMinimumDate:[[NSCalendar currentCalendar] startOfDayForDate:[NSDate date]]];
}
[self updateStartTimeField:nil];
}

UIDatePicker: While selecting date, it jumps to any random date

I have been trying to fix this issue since so long but did not find any way to sort this out.
When I'm trying to select a year sometimes the year component of the date picker jumps to a random year. (The same thing happens with date and month selection)
The data picker is contained in a UIView and I have created an IBOutlet for it.
- (void)setupforBirthdates {
[self.dtPicker setDatePickerMode: UIDatePickerModeDate];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier: NSCalendarIdentifierGregorian];
NSDate *currentDate = [NSDate date];
NSDateComponents * comps = [[NSDateComponents alloc] init];
[comps setYear: -17];
NSDate * maxDate = [gregorian dateByAddingComponents: comps toDate: currentDate options: NSCalendarMatchStrictly];
[comps setYear: -50];
NSDate * minDate = [gregorian dateByAddingComponents: comps toDate: currentDate options: NSCalendarMatchStrictly];
[self.dtPicker setMinimumDate:minDate];
[self.dtPicker setMaximumDate:maxDate];
[self.dtPicker setDate:maxDate];
}
ISSUE See the below image...
I thought that it may be due to some 3rd party libraries this is happening. I have the following pod in my project
pod 'AFNetworking'
pod 'GoogleMaps'
pod 'GooglePlaces'
pod 'Fabric'
pod 'Crashlytics'
pod 'RACollectionViewReorderableTripletLayout'
pod 'FBSDKLoginKit'
pod 'Socket.IO-Client-Swift', '~> 13.3.0'
How can I solve this issue?
Any help/suggestions?
UPDATE
I what to restrict user to select birth year from 17 to 50 year only so the minDate will be 17 years back from current year
maxDate will be 50 years back from the current year
The issue is also coming if I don't set minDate and maxDate
Tested the following case too
I just drag and drop new date picker on screen. I did not set any min/max date, nor connect an IBOutlet and I run app and when I scroll to any date the same issue is coming
You will be surprised that I have created a custom date picker using UIPickerView and the issue is still there.
When I have created a new demo project and copy pasted the code in demo project then this issue is not coming. I've tested it many times on demo project the issue is not coming.
The following func. is called when I change the date in date picker.
- (IBAction)datePickerValueChanged:(id)sender {
NSDateFormatter *dateFormat=[[NSDateFormatter alloc]init];
[dateFormat setDateFormat:#"yyyy-MM-dd"];
self.txtBirthday.text = [NSString stringWithFormat:#"%#",[dateFormat stringFromDate:self.dtPicker.date]];
}
The strange thing is that for the When I just put(drag & drop) UIDatePicker View on a screen just to test its scrolling issue. When I scroll date time picker view then also it was scrolling at random location.
I feel that it is the issue with third party library.
After many hours of debugging and trail-run, I finally found the third party library which was the source of this issue.
Actually is was the category name is UITableView+SPXRevealAdditions.
When I removed it UIDatePicker is working fine and when I re-added the issue is started occurring.
It is really very strange but It worked for me.:D
Update:
I wanted the that 3rd party too. So what I did id added a dummy pan gesture in viewDidLoadMethod:.
UIPanGestureRecognizer *p = [[UIPanGestureRecognizer alloc] initWithTarget:nil action:#selector(doNothing)];
[self.dtPicker addGestureRecognizer:p];
and the dummy method.
- (void)doNothing {
printf("do nothing");
}
This solved my problem and Now the UIDatePicker is working fine and also third party library too...cheers...:D.
You can check whenever your picker want to change the label value by comparing it with the min and max date, here the code *please swap the Ascending and descending if my code do wrong
- (IBAction)datePickerValueChanged:(id)sender {
NSDateFormatter *dateFormat=[[NSDateFormatter alloc]init]; [dateFormat setDateFormat:#"yyyy-MM-dd"];
NSDate * maxDate = [gregorian dateByAddingComponents: comps toDate: currentDate options: NSCalendarMatchStrictly];
[comps setYear: -50];
NSDate * minDate = [gregorian dateByAddingComponents: comps toDate: currentDate options: NSCalendarMatchStrictly];
NSDate * curDate = self.dtPicker.date;
if(([curDate compare:minDate] == NSOrderedAscending)&& ([curDate compare:maxDate] == NSOrderedDescending)){
self.txtBirthday.text = [NSString stringWithFormat:#"%#",[dateFormat stringFromDate:self.dtPicker.date]];
}
}
class ViewController: UIViewController {
#IBOutlet weak var datePicker: UIDatePicker!
#IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.configureDatePicker()
}
private func configureDatePicker() {
let calendar = Calendar(identifier: .gregorian)
// 17 years less
let minimumDate = calendar.date(byAdding: .year, value: -17, to: Date())
// 50 years max. 17 + 33 = 50
let maximumDate = calendar.date(byAdding: .year, value: -50, to: Date())
self.datePicker.minimumDate = minimumDate
self.datePicker.maximumDate = maximumDate
}
#IBAction func onDatePickerChanged(sender: UIDatePicker) {
let dateFormtter = DateFormatter()
dateFormtter.dateStyle = .medium
self.label.text = dateFormtter.string(from: sender.date)
}
}
This code works fine without any issue. I think you have some issue in your code. UIDatePicker is resetting in some places.

Why does UITableView shows only half the data when coming back to front

I have a very strange behavior of my UITableView. When I call it first time after starting the app all data are shown as they should. When I move to another Viewcontroller and come back to the tableview it only shows half the data. I figured out that [tableview reloaddata] in viewwillappear causes the issue. If I comment it out, all data stay as they were. Therefore I suppose that something is going wrong while retrieving the data when coming back. I need to tell that the data are coming from 2 different arrays which fill labels in a custom UITableViewCell. As I have some other difficulties with the setup of this cell (labels don't work compliant to the set constraints) first I thought maybe the labels are out of view. But now I'm pretty sure that the data of one of the arrays are gone.
Does anyone know, if there is a difference of loading data for the first time and reload data? Is it maybe a timing problem and the tableviewcontroller does not have enough time to retrieve the data? If yes what can I do against it? Could there are other reasons why it doesn't work?
Please tell me if I should post some code. I did not know what to show to solve the issue.
Thank you in advance for your appreciate help.
`
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self fetchAllTermine]; //method to retrieve data from array #1
NSLog(#"viewWillAppear: %#", [self fetchAllTermine]);//logfile always shows data
events = (NSMutableArray*) [self getEventsFromCalendar]; //method to retrieve data from array #2 , events is a global variable
[self.tableView reloadData];//after reloadData data from array #1 are missing
}
-(NSMutableArray*)fetchAllTermine
{
NSFetchRequest<Termine *> *tfetchRequest = [Termine fetchRequest];
NSError *error ;
NSMutableArray * fetchedTermine = [[[self managedObjectContext] executeFetchRequest:tfetchRequest error:&error]mutableCopy];
self.termineArray = [[[self managedObjectContext] executeFetchRequest:tfetchRequest error:&error]mutableCopy];
// NSLog(#"fetchAllTermine in MonatTVC: %#", self.termineArray);
return fetchedTermine;
}
-(NSArray*)getEventsFromCalendar
{
[[EKEventStore new] requestAccessToEntityType:EKEntityTypeEvent completion:^(BOOL granted, NSError *error) {
if (granted) {
NSLog(#"Access to calendar granted");
} else {
NSLog(#"No access to calendar");
}
}];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSArray *calendars = [[EKEventStore new] calendarsForEntityType:EKEntityTypeEvent];
NSDateComponents *tomorrowComponents = [[NSDateComponents alloc] init];
tomorrowComponents.month = 0;
NSDate *tomorrow = [calendar dateByAddingComponents:tomorrowComponents
toDate:[NSDate date]
options:0];
// Create the end date components
NSDateComponents *afterTomorrowComponents = [[NSDateComponents alloc] init];
afterTomorrowComponents.month = +1;
NSDate *afterTomorrow = [calendar dateByAddingComponents:afterTomorrowComponents
toDate:[NSDate date]
options:0];
NSPredicate *predicate = [[EKEventStore new] predicateForEventsWithStartDate:tomorrow
endDate:afterTomorrow
calendars:calendars];
NSArray *eventListe = [[EKEventStore new] eventsMatchingPredicate:predicate];
return eventListe;
}
`
coming back to the view
first call of the view with all data shown
You shoud copy array data to show it on the cell. Otherwise you will not get the total data you wanted to show.
Thanks to all who answered my question. Now I found the solution to my problem. After first initializing I overwrote the terminData-Array everytime when I was coming back to the tableview. Everything works fine now and I can use both arrays parallel to fill in data in the tableview.
BR
Debhelapara
After a quick glance at what can be wrong with your code. Having reloadData in viewWillAppear() is not ok:
First of all, viewWillAppear is called when the view is not yet
visible and reloadData causes redraw and other operations that
depend/need the visible view (for example, heights of cells);
Second, the table will be redrawn anyways when the view becomes
visible, so your reloadData is useless here;
viewWillAppear() is called every time your view becomes visible
after closing the child view controller. Do you really want the table to
reload with flickering and scrolling at the origin every time in
a situation like that?
Except this, there is not enough code to see what else can be wrong. How the table is initialized in viewDidLoad, how cells are created and populated, etc.

NSTimeIntervalSinceDate gives 86,399 seconds between consecutive days, why?

In iOS, Xcode9, and Obj-C, I am trying to find out how much time has elapsed in days between two dates. I know the NSTimeIntervalSince method yields a result in seconds. But it seems that when I calculate the seconds between consecutive days (like 11-2-2016 and 11-3-2016), I am 1 second short, yielding 86,399. If I calculate seconds between larger intervals, I am always a second short.
11-2-2016 to 11-4-2016: 172,799 (two 24-hour days but missing a second)
11-2-2016 to 11-5-2016: 259,199 (three 24-hour days but missing a second)
Here's my code:
#property (strong, nonatomic) NSDate *firstDate;
#property (strong, nonatomic) NSDate *secondDate;
#synthesize firstDate, secondDate;
int secondsIntervalFirstDatetoSecondDate = (fabs([firstDate timeIntervalSinceDate:secondDate]));
NSLog(#"seconds between firstDate and secondDate %i", secondsIntervalFirstDatetoSecondDate);
firstDate and secodDate are NSDate
They are entered by the user using a datePicker and date formatting is set as
[formatter setDateFormat:#"MM-dd-yyyy"];
I've searched for an answer but could find none.
First post for a newbie, sorry for any etiquette errors, I'll try to improve.
When you create a UIDatePicker and put it in "date" mode, the time is the time the date picker was created. If you're creating two pickers, they're going to be created at slightly different times. Even a very small difference in those times can lead to a 1-second difference.
You should never compute time-differences this way. There are not 86,400 seconds in a day. "How many days are between two points in time" is complicated, and you should use the tools designed for it: NSDateComponents and NSCalendar.
NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
NSInteger diffInDays = [[calendar components:NSCalendarUnitDay
fromDate:[calendar startOfDayForDate:date1]
toDate:[calendar startOfDayForDate:date2]
options:0] day];

iOS: Make Tapku calendar library tiles grid size to 6x6 always

I noticed that Tapku calendar grid resized between 5x5 and 6x6 depending on the month's dates distribution. For example it displays 5x5 grid for March 2012 and displays 6x6 grid for September 2012! For me it makes GUI alignments go wrong so I want grid to be always 6x6. I have been looking into TKCalenderMonthView's rangeOfDatesInMonthGrid method but not getting how it creates the grid! Could anyone please tell me how to fix the grid 6x6 always.
Thanks.
Solution to 2nd Point.If you want to display a mark on selected and remove mark from deselected dates then use follwoing code.(It wont display blue mark)
- (void)calendarMonthView:(TKCalendarMonthView *)monthView didSelectDate:(NSDate *)d {
NSLog(#"calendarMonthView didSelectDate");
NSDateFormatter *df=[[NSDateFormatter alloc] init];
[df setDateFormat:#"yyyy-MM-dd"];
[df setTimeZone:[NSTimeZone systemTimeZone]];
NSString *strqw=[df stringFromDate:d];
NSLog(#"%#",strqw);
NSString *stss=[strqw stringByAppendingString:#" 00:00:00 +0000"];
NSLog(#"%#",stss);
int k=0;
for (int i=0; i<[array1 count]; i++) {
if([[array1 objectAtIndex:i]isEqualToString:stss]){
[array1 removeObjectAtIndex:i];
k=1;
}
}
if(k==0)
[array1 addObject:stss];
[calendar reload];
}
And add this line
NSArray *data=[[NSArray alloc] initWithArray:array1];
in the below method
- (NSArray*)calendarMonthView:(TKCalendarMonthView *)monthView marksFromDate:(NSDate *)startDate toDate:(NSDate *)lastDate
Here's a little hack I use:
In the viewDidAppear I have
[calendar selectDate:[NSDate dateWithTimeIntervalSinceNow:-31*24*60*60]];
[calendar selectDate:[NSDate dateWithTimeIntervalSinceNow:0]];
And in the
- (void) calendarMonthView:(TKCalendarMonthView*)monthView monthDidChange:(NSDate*)month animated:(BOOL)animated{
I just check the height of my calendar and do whatever I need to do. This is done because if you check the height of the frame immediately after instantiation of the calendar, it will return the normal 5*7 height instead of the 6*7.
Hope that helps!

Resources