#ios #bar-chart #uiviewanimation
#iOS #гистограмма #uiviewanimation
Вопрос:
Я пытаюсь создать простую гистограмму, показывающую относительную продолжительность последовательно записанных действий, и я не могу заставить ее отображаться должным образом. Он основан на простых UIView
анимациях, и некоторые его части, похоже, работают, а именно тень под панелью. Однако сами столбцы никогда не отображаются.
Я вдвойне сбит с толку, потому что я очень точно смоделировал код на другой гистограмме в моем приложении, которая ДЕЙСТВИТЕЛЬНО работает. Единственное реальное различие — это исходные данные и ориентация столбцов.
Вот код, за которым следует вывод на консоль:
-(void) displayDayChart
{
NSTimeInterval timeFrame = -86400; // 24 hours for this test, selectable in real life
NSDate *dayStart = [NSDate dateWithTimeIntervalSinceNow:timeFrame];
NSDate *ratNow = [NSDate date];
int y = (self.chartView.frame.size.height) - 5;
NSLog(@"DayStart is %@",dayStart);
// Data source
// Predicate to retrieve activities that stopped after the beginning of the timeframe, plus the currently running one
actPredicate = [NSPredicate predicateWithFormat:@"(startTime >= %@ AND stopTime <= %@) OR ((startTime <= %@ AND stopTime >= %@) OR (startTime <= %@ AND stopTime == NULL))",dayStart,ratNow,dayStart,dayStart,ratNow];
// Fetch the activities
NSFetchedResultsController *dayActivityFRC = [TimedActivity MR_fetchAllSortedBy:@"startTime" ascending:NO withPredicate:actPredicate groupBy:nil delegate:nil];
// int taCount = [TimedActivity MR_countOfEntities];
// NSLog(@"total of TimedActivities is %d",taCount);
int grabbedActivities = dayActivityFRC.fetchedObjects.count;
NSLog(@"total of grabbedActivities is %d",grabbedActivities);
NSLog(@"Number of TimedActivities in dayActivityFRC is %d",dayActivityFRC.fetchedObjects.count);
DayChartBar *thisBar;
TimedActivity *thisItem;
for(int i=0; i<(dayActivityFRC.fetchedObjects.count); i )
{
thisBar = [[DayChartBar alloc] initWithFrame:CGRectZero];
thisBar.tag = i 1;
[self.chartView addSubview:thisBar];
thisItem = [dayActivityFRC.fetchedObjects objectAtIndex:i];
// Increment vertical location of bar
y = y - 20;
// Calculate top (currently timing) activity's duration
if (thisItem.stopTime == nil)
{
NSNumber *n = ([NSNumber numberWithDouble: abs([thisItem.startTime timeIntervalSinceDate:[NSDate date]])]);
thisItem.duration = n;
}
// Calculate bottom activity's duration
if (thisItem.startTime < dayStart amp;amp; thisItem.stopTime > dayStart)
{
NSNumber *n = ([NSNumber numberWithDouble: abs([thisItem.stopTime timeIntervalSinceDate:dayStart])]);
thisItem.duration = n;
// NSLog(@"%@ is the bottom item",thisItem.name);
}
// Calculate middle activities' duration
if (thisItem.startTime > dayStart amp;amp; thisItem.stopTime < ratNow)
{
NSNumber *n = ([NSNumber numberWithDouble: abs([thisItem.stopTime timeIntervalSinceDate:thisItem.startTime])]);
thisItem.duration = n;
}
NSLog(@"Check loop %@",thisItem.name);
NSLog(@"startTime is %@",thisItem.startTime);
NSLog(@"stopTime is %@",thisItem.stopTime);
NSLog(@"duration is %@n",thisItem.duration);
// Width of view = 280
// Calculate width of bar (proportionate to length of activity vs timeframe, relative to available space in chart view)
int w = ((280) * ([thisItem.duration doubleValue])) / (abs(timeFrame));
NSLog(@"w = %d",w);
// Make an animated bar of the appropriate color and size
[UIView animateWithDuration:.3
delay:.2
options: UIViewAnimationCurveEaseOut // Deprecated, but still works
animations:^
{
// Starting state
thisBar.frame = CGRectMake(20, y, 0, 15);
thisBar.backgroundColor = [UIColor blackColor];
// End state
thisBar.frame = CGRectMake(20, y, w, 15);
NSLog(@"thisBar.frame is %@",NSStringFromCGRect (thisBar.frame));
thisBar.backgroundColor = thisItem.color;
thisBar.layer.shadowColor = [[UIColor blackColor] CGColor];
thisBar.layer.shadowOpacity = 0.7;
thisBar.layer.shadowRadius = 4.0;
thisBar.layer.shadowOffset = CGSizeMake(5.0f, 5.0f);
thisBar.layer.shadowPath = [UIBezierPath bezierPathWithRect:thisBar.bounds].CGPath;
NSLog(@"Bar created!");
}
completion:^(BOOL finished)
{
// Reserved for creating a name label at the end of each bar
NSLog(@"Bar completed!");
}];
}
}
И вывод на консоль:
2014-06-20 11:05:17.910 WMDGx[46607:a0b] Number of activities is 2
2014-06-20 11:05:22.793 WMDGx[46607:a0b] DayStart is 2014-06-19 18:05:22 0000
2014-06-20 11:05:22.794 WMDGx[46607:a0b] total of grabbedActivities is 8
2014-06-20 11:05:22.795 WMDGx[46607:a0b] Number of TimedActivities in dayActivityFRC is 8
2014-06-20 11:05:22.796 WMDGx[46607:a0b] Check loop Dusting
2014-06-20 11:05:22.796 WMDGx[46607:a0b] startTime is 2014-06-20 17:29:04 0000
2014-06-20 11:05:22.797 WMDGx[46607:a0b] stopTime is (null)
2014-06-20 11:05:22.797 WMDGx[46607:a0b] duration is 0
2014-06-20 11:05:22.798 WMDGx[46607:a0b] w = 0
2014-06-20 11:05:22.798 WMDGx[46607:a0b] thisBar.frame is {{20, 261}, {0, 15}}
2014-06-20 11:05:22.799 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.800 WMDGx[46607:a0b] Check loop Test 1
2014-06-20 11:05:22.800 WMDGx[46607:a0b] startTime is 2014-06-20 17:19:22 0000
2014-06-20 11:05:22.801 WMDGx[46607:a0b] stopTime is 2014-06-20 17:29:04 0000
2014-06-20 11:05:22.801 WMDGx[46607:a0b] duration is 581
2014-06-20 11:05:22.802 WMDGx[46607:a0b] w = 1
2014-06-20 11:05:22.803 WMDGx[46607:a0b] thisBar.frame is {{20, 241}, {1, 15}}
2014-06-20 11:05:22.803 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.804 WMDGx[46607:a0b] Check loop Dusting
2014-06-20 11:05:22.804 WMDGx[46607:a0b] startTime is 2014-06-20 16:52:10 0000
2014-06-20 11:05:22.805 WMDGx[46607:a0b] stopTime is 2014-06-20 17:19:22 0000
2014-06-20 11:05:22.805 WMDGx[46607:a0b] duration is 1632
2014-06-20 11:05:22.806 WMDGx[46607:a0b] w = 5
2014-06-20 11:05:22.808 WMDGx[46607:a0b] thisBar.frame is {{20, 221}, {5, 15}}
2014-06-20 11:05:22.809 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.810 WMDGx[46607:a0b] Check loop Test 1
2014-06-20 11:05:22.811 WMDGx[46607:a0b] startTime is 2014-06-20 16:52:04 0000
2014-06-20 11:05:22.811 WMDGx[46607:a0b] stopTime is 2014-06-20 16:52:10 0000
2014-06-20 11:05:22.812 WMDGx[46607:a0b] duration is 6
2014-06-20 11:05:22.812 WMDGx[46607:a0b] w = 0
2014-06-20 11:05:22.813 WMDGx[46607:a0b] thisBar.frame is {{20, 201}, {0, 15}}
2014-06-20 11:05:22.813 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.814 WMDGx[46607:a0b] Check loop Timer Sleeping
2014-06-20 11:05:22.814 WMDGx[46607:a0b] startTime is 2014-06-20 16:29:06 0000
2014-06-20 11:05:22.816 WMDGx[46607:a0b] stopTime is 2014-06-20 16:52:04 0000
2014-06-20 11:05:22.816 WMDGx[46607:a0b] duration is 1378
2014-06-20 11:05:22.817 WMDGx[46607:a0b] w = 4
2014-06-20 11:05:22.818 WMDGx[46607:a0b] thisBar.frame is {{20, 181}, {4, 15}}
2014-06-20 11:05:22.818 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.820 WMDGx[46607:a0b] Check loop Dusting
2014-06-20 11:05:22.821 WMDGx[46607:a0b] startTime is 2014-06-20 16:28:53 0000
2014-06-20 11:05:22.821 WMDGx[46607:a0b] stopTime is 2014-06-20 16:29:06 0000
2014-06-20 11:05:22.822 WMDGx[46607:a0b] duration is 12
2014-06-20 11:05:22.823 WMDGx[46607:a0b] w = 0
2014-06-20 11:05:22.824 WMDGx[46607:a0b] thisBar.frame is {{20, 161}, {0, 15}}
2014-06-20 11:05:22.825 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.826 WMDGx[46607:a0b] Check loop Test 1
2014-06-20 11:05:22.827 WMDGx[46607:a0b] startTime is 2014-06-20 16:28:38 0000
2014-06-20 11:05:22.827 WMDGx[46607:a0b] stopTime is 2014-06-20 16:28:53 0000
2014-06-20 11:05:22.827 WMDGx[46607:a0b] duration is 14
2014-06-20 11:05:22.828 WMDGx[46607:a0b] w = 0
2014-06-20 11:05:22.828 WMDGx[46607:a0b] thisBar.frame is {{20, 141}, {0, 15}}
2014-06-20 11:05:22.829 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:22.829 WMDGx[46607:a0b] Check loop Timer Sleeping
2014-06-20 11:05:22.829 WMDGx[46607:a0b] startTime is 2014-06-20 16:25:35 0000
2014-06-20 11:05:22.830 WMDGx[46607:a0b] stopTime is 2014-06-20 16:28:38 0000
2014-06-20 11:05:22.831 WMDGx[46607:a0b] duration is 183
2014-06-20 11:05:22.832 WMDGx[46607:a0b] w = 0
2014-06-20 11:05:22.834 WMDGx[46607:a0b] thisBar.frame is {{20, 121}, {0, 15}}
2014-06-20 11:05:22.834 WMDGx[46607:a0b] Bar created!
2014-06-20 11:05:23.348 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.350 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.351 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.352 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.352 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.353 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.354 WMDGx[46607:a0b] Bar completed!
2014-06-20 11:05:23.355 WMDGx[46607:a0b] Bar completed!
Я надеюсь, что это просто тупой случай, когда вы не видите леса за деревьями, но я выбивал себе мозги в течение 3 дней, прежде чем довести это до SO. Я знаю, что это не сайт для корректуры.
Вот скриншот, показывающий тени (и отсутствие самих полос). Тени, по-видимому, находятся в правильном месте и имеют правильный размер на основе данных:
**Редактировать*************
Следуя комментариям rdelmar и @gro ниже, я изменил строку:
thisBar.backgroundColor = thisItem.color;
Для:
thisBar.backgroundColor = [UIColor redColor];
Который создал этот снимок экрана:
Итак, полагая, что проблема была выявлена, я вернулся и изменил это:
thisBar = [[DayChartBar alloc] initWithFrame:CGRectZero];
thisBar.tag = i 1;
[self.chartView addSubview:thisBar];
thisItem = [dayActivityFRC.fetchedObjects objectAtIndex:i];
к этому
thisBar = [[DayChartBar alloc] initWithFrame:CGRectZero];
thisBar.tag = i 1;
[self.chartView addSubview:thisBar];
thisItem = [dayActivityFRC.fetchedObjects objectAtIndex:i];
thisBar.endColor = thisItem.color;
и это (в блоке анимации):
thisBar.backgroundColor = thisItem.color;
к этому:
thisBar.backgroundColor = thisBar.endColor;
И теперь столбцы снова исчезли.
** Второе редактирование*****************
Мне пришлось немного вернуться назад, но теперь столбцы отображаются, хотя и немного странно. Проблема (по крайней мере, основная) заключалась в том, что цвета, присвоенные каждому элементу через связанную с ним категорию, затем передаются в TimedActivity, которые представлены столбцами. Да, я знаю, довольно запутанный. Мне нужно разобраться в ее очистке.
В любом случае, так это выглядит сейчас. Как я уже сказал, поведение немного странное — например, на верхней панели есть только тень и нет полосы, но, по крайней мере, я вижу несколько цветных полос. Однако тени, по необъяснимой причине, создаются перед самими столбцами. Или так могло бы показаться.
Комментарии:
1. Я создал упрощенную версию вашего кода, удалив все данные и заменив их массивом, чтобы указать ширину столбцов. Я также сделал UIViews баров вместо DayChartBar. Таким образом, код рисования был одинаковым, и столбцы отображались правильно. Итак, проблема, похоже, связана с данными, управляющими столбцами, но я еще не заметил этого.
2. Спасибо, что посмотрели! Я должен был упомянуть, что ранее я заметил аномалию в отчете о продолжительности, но полагал, что исправил это, используя предикат, как вы его видите. Предыдущий предикат был проще, но, похоже, каким-то образом создавал проблему. Текущий предикат, похоже, долгое время работал правильно в коде, на котором я смоделировал этот метод.
3. Кстати, я уверен, что вы видели показания данных о продолжительности в консоли, да?
4. это то, что вы хотели здесь? thisBar.backgroundColor = thisItem.color;
5. ДА. У этого элемента есть свойство .color из соответствующей категории.
Ответ №1:
Я подумал, что завершу это, поскольку никто ничего не вносил в течение 24 часов, и проблема, как указано, была решена.
Предполагалось, что цвет каждого столбца будет задаваться с помощью своего рода круговой схемы взаимосвязей основных данных. Как только я это исправил, цветные полосы появились, как и ожидалось.
Другая (неустановленная) проблема заключается в том, что существует некоторая кажущаяся случайность в длинах столбцов относительно доступного пространства. На данный момент я рассматриваю это как арифметическую проблему.
Спасибо @rdelmar и @gro, оба комментария которых указали мне на проблему с основными данными.