Головоломка со столбчатой диаграммой / анимацией UIView

#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, оба комментария которых указали мне на проблему с основными данными.