Как правильно определить левое поле расширения «Сегодня» в iOS 8?

Я пытаюсь выяснить, как рассчитать левое поле в главном представлении расширения «Сегодня», чтобы выровнять содержимое с остальными метками представления «Сегодня».

Вот пример с чистым проектом Xcode с использованием расширений Today (я добавил цвет к фону представления и нарисовал пунктирную красную линию, чтобы показать, где я хотел бы выровнять Hello World UILabel).

Результат в симуляторе iPhone 6 Plus (слева пейзаж, справа портрет) можно увидеть на изображении ниже:

введите здесь описание изображения

На изображении обратите внимание, что зеленая левая граница основного вида размещена по-разному в зависимости от имени приложения UILabel "testi2". Также кажется, что красная линия — выравнивание левой границы основных видов отличается на каждом устройстве: iPhone 5x, iPhone 6 и iPad.

Поведение можно воспроизвести с помощью чистого проекта Xcode (я использую Xcode 6.1.1, iOS 8.1 и Swift):

  1. Создайте пустой проект Xcode (приложение с одним представлением)
  2. Добавить новую цель: Расширения > Расширение «Сегодня».
  3. В группе расширений Today найдите MainInterface.storyboard и сделайте фон основного вида зеленым, а фон Hello world UILabel красным: enter image  описание здесь

Как выровнять Hello World UILabel (красный фон) по пунктирной линии? Или как выровнять основной вид (зеленый фон) по пунктирной линии?


person Markus Rautopuro    schedule 28.12.2014    source источник
comment
Изображение битое, по крайней мере здесь. Вы запросили страницу на веб-сайте (i.stack.imgur.com), который находится в сети CloudFlare. CloudFlare в настоящее время не может разрешить запрошенный вами домен (i.stack.imgur.com).   -  person Duncan Babbage    schedule 28.12.2014
comment
На самом деле, это похоже на проблему StackOverflow. Только что заметил еще одно неработающее изображение, связанное с сайтом. Игнорировать.   -  person Duncan Babbage    schedule 28.12.2014
comment
Хорошо, вот еще одна ссылка на изображение: ibin.co/w800/1mDY3ckx95h7   -  person Markus Rautopuro    schedule 28.12.2014
comment
Я бы подумал, что представление «Сегодня» правильно выровняет их, если вы не установили поля, хотя я не проверял это. Какой код дает результаты на скриншоте?   -  person Duncan Babbage    schedule 28.12.2014
comment
См. отредактированный вопрос: простое добавление цвета к стандартному шаблону Interface Builder расширения Today приводит к странному выравниванию в портретном и альбомном режимах.   -  person Markus Rautopuro    schedule 29.12.2014
comment
Как отметил @dehlen, в этой теме обсуждаются поля: stackoverflow.com/questions/26025139/, однако представленное там решение требует выяснения значений магических пикселей для каждого устройства и ориентации.   -  person Markus Rautopuro    schedule 02.01.2015


Ответы (3)


Вы пробовали этот?

Цель-C:

- (UIEdgeInsets)widgetMarginInsetsForProposedMarginInsets:(UIEdgeInsets)defaultMarginInsets
{
    return UIEdgeInsetsZero;
}

Свифт:

func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets {
        return UIEdgeInsetsZero
}

В противном случае, похоже, вам придется установить их вручную в соответствии с этим So-Thread:

ИЗМЕНИТЬ:

Похоже, этот метод устарел и не вызывается для устройств под управлением >= iOS10. Однако я не смог найти никакой документации по альтернативе. Если у вас есть какая-либо информация об этом, пожалуйста, добавьте в этот пост, чтобы каждый мог получить прибыль. Просто убедитесь, что при использовании этой функции она не будет вызываться на >= iOS10.

Источник: документация Apple

person dehlen    schedule 02.01.2015
comment
Спасибо, позвольте мне попробовать это. Я ищу решение, которое не требует ввода значений магических пикселей для каждого устройства и ориентации. - person Markus Rautopuro; 02.01.2015
comment
Пример (я использую Swift, как упоминалось в вопросе, кстати), который вы предоставили, действительно убирает все поля. Однако он не отвечает, как рассчитать положение (красная полосатая линия на моем снимке экрана) имени виджета UILabel. - person Markus Rautopuro; 02.01.2015

Я попытался использовать значение left для defaultMarginInset из -widgetMarginInsetsForProposedMarginInsets со смешанными результатами: на размерах экрана iPhone 5S его можно использовать для получения той же вставки, что и виджет календаря по умолчанию в iOS (обратите внимание, что правое поле метки времени совпадает с синяя линия):

5S Portrait

5S Пейзаж

На iPhone 6 вы получите похожие результаты, т. е. тоже совпадет. Однако на iPhone 6 Plus виджет календаря каким-то образом масштабирует вставку:

6P Portrait

6P Пейзаж

Обратите внимание, что в альбомной версии ни время, ни линии не совпадают ни с чем.

В заключение скажу, что можно смело использовать defaultMarginInset.left для получения достойных результатов.


Свифт-код:

class TodayViewController: UIViewController, NCWidgetProviding {

    var defaultLeftInset: CGFloat = 0
    var marginIndicator = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()

        marginIndicator.backgroundColor = UIColor.whiteColor()
        view.addSubview(marginIndicator)
    }

    func widgetMarginInsetsForProposedMarginInsets(var defaultMarginInsets: UIEdgeInsets) -> UIEdgeInsets {
        defaultLeftInset = defaultMarginInsets.left

        defaultMarginInsets.left = 0
        return defaultMarginInsets
    }

    func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
        marginIndicator.frame = CGRectMake(defaultLeftInset, 0, 10, view.frame.size.height)
        completionHandler(NCUpdateResult.NewData)
    }
}
person fabian789    schedule 02.01.2015
comment
Это прилично, но это не точно. Apple как-то выравнивает, интересно как. Бьюсь об заклад, у них нет фиксированного набора значений пикселей для каждого устройства и ориентации. - person Markus Rautopuro; 02.01.2015
comment
Я бы не был так уверен в этом. Кроме того, как вы видите на 6 Plus, он ни с чем не согласуется. Кроме того, если вы сравните вставки виджета «Напоминания» с виджетом календаря, вы заметите, что он вообще ничего не выравнивает. Мне кажется, они не так строги в этом, к сожалению... - person fabian789; 02.01.2015
comment
В горизонтальной ориентации iPhone 6 Plus текст У вас нет запланированных мероприятий на завтра. идеально сочетается с заголовком виджета «Завтра» (виджет «Tomorrow Summary Today» от Apple). - person Markus Rautopuro; 02.01.2015
comment
А, этого я не заметил. Тем не менее, Apple, возможно, также жестко запрограммировала некоторые значения, которые они не раскрывают публично: например, высоту клавиатуры. - person fabian789; 02.01.2015

Мое временное решение выглядит следующим образом. Я использую постоянные значения для установки левого и верхнего полей. Таким образом, я могу выровнять содержимое точно так же, как, например, в виджете Tomorrow Summary.

Сначала несколько вспомогательных методов для определения типа устройства (адаптировано из этого ответа):

struct ScreenSize {
    static let SCREEN_WIDTH = UIScreen.mainScreen().bounds.size.width
    static let SCREEN_HEIGHT = UIScreen.mainScreen().bounds.size.height
    static let SCREEN_MAX_LENGTH = max(ScreenSize.SCREEN_WIDTH,
        ScreenSize.SCREEN_HEIGHT)
    static let SCREEN_MIN_LENGTH = min(ScreenSize.SCREEN_WIDTH,
        ScreenSize.SCREEN_HEIGHT)
}

struct DeviceType {
    static let iPhone4 =  UIDevice.currentDevice().userInterfaceIdiom == .Phone
        && ScreenSize.SCREEN_MAX_LENGTH < 568.0
    static let iPhone5 = UIDevice.currentDevice().userInterfaceIdiom == .Phone
        && ScreenSize.SCREEN_MAX_LENGTH == 568.0
    static let iPhone6 = UIDevice.currentDevice().userInterfaceIdiom == .Phone
        && ScreenSize.SCREEN_MAX_LENGTH == 667.0
    static let iPhone6Plus = UIDevice.currentDevice().userInterfaceIdiom == .Phone
        && ScreenSize.SCREEN_MAX_LENGTH == 736.0
    static let iPad = UIDevice.currentDevice().userInterfaceIdiom == .Pad
}

Затем, используя widgetMarginInsetsForProposedMarginInsets:, как было предложено, я перезаписываю левую и верхнюю вставки следующим образом:

func widgetMarginInsetsForProposedMarginInsets(defaultMarginInsets: UIEdgeInsets)
        -> UIEdgeInsets {
    var insets = defaultMarginInsets
    let isPortrait = UIScreen.mainScreen().bounds.size.width
        < UIScreen.mainScreen().bounds.size.height

    insets.top = 10.0
    if DeviceType.iPhone6Plus {
        insets.left = isPortrait ? 53.0 : 82.0
    } else if DeviceType.iPhone6 {
        insets.left = 49.0
    } else if DeviceType.iPhone5 {
        insets.left = 49.0
    } else if DeviceType.iPhone4 {
        insets.left = 49.0
    } else if DeviceType.iPad {
        insets.left = isPortrait ? 58.0 : 58.0
    }

    return insets
}

Однако это не то решение, которое я ищу - я хотел бы избавиться от жесткого кодирования значений пикселей для каждого устройства и ориентации.

person Markus Rautopuro    schedule 02.01.2015
comment
Для iPad Portait вы должны использовать 54 вместо 58, иначе у меня сработало - person mohlendo; 11.03.2015