CALayer angleRadius не влияет на 4-дюймовое устройство (симулятор)

Я работаю над динамической, программной компоновкой представления для 3,5-дюймовых устройств, а также для 4-дюймовых устройств. Таким образом, это работает нормально. Но мне нужны закругленные углы, чтобы мои изображения выглядели как игральные карты. И я получаю закругленные углы, красиво отображаемые на 3,5-дюймовых устройствах в симуляторе для симуляции iOS 6.1 и 7. Но когда я выбираю iPhone Retina 4 дюйма на 6.1 или 7, UIImage в UIImageView отображается полностью. Он прекрасно работает на симулированных устройствах iPad (в режиме симуляции iPhone — это приложение только для iPhone).

На сегодняшний день у меня нет с собой 4-дюймового устройства, чтобы протестировать его. Я могу протестировать устройство в течение следующей недели.

Вот соответствующий код:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    self.imageV.image = self.image; // The image property was set by the caller.

    // Layout imageV within self.view with a margin of MARGIN
    self.imageV.frame = CGRectMake(self.view.frame.origin.x + MARGIN, self.view.frame.origin.y + MARGIN, self.view.frame.size.width - 2 * MARGIN, self.view.frame.size.height - 2 * MARGIN);

    // set the raidus and the mask to follow the rounded corners.
    self.imageV.layer.cornerRadius = CORNER_RADIUS;
    self.imageV.layer.masksToBounds = YES;
}

Кстати: CORNER_RADIUS равен 18, а MARGIN равен 15. Изменение этих значений не влияет на проблему.

ОБНОВЛЕНИЕ: благодаря Мэтту я понял, что проблема исчезает, когда я программно создаю UIImageView. Это действительно хороший обходной путь, плюс он указывает в правильном направлении, я думаю, но это не решение. Любые идеи, какие настройки в редакторе раскадровки могли вызвать проблему? Насколько я вижу, автоматическая компоновка отключена для всех контроллеров представления в этой раскадровке.

3.5 устройство4 устройства


person Hermann Klecker    schedule 30.03.2014    source источник
comment
Очевидно, что в вашем коде все в порядке, поэтому я должен верить, что здесь происходит что-то еще.   -  person matt    schedule 30.03.2014
comment
Позвольте мне просто проверить пару вещей с вами. Где создается представление изображения? Если в раскадровке / пере, включена ли автоматическая компоновка? Если это так, у вас проблема, потому что вы не можете установить фрейм напрямую.   -  person matt    schedule 30.03.2014
comment
Кроме того, когда вы говорите frame, вы должны говорить bounds - фрейм представления изображения позиционируется относительно границы self.view, а не его фрейма.   -  person matt    schedule 30.03.2014
comment
Однако, исправив все это, я не могу воспроизвести проблему, поэтому я предполагаю, что у вас есть другой код, который вы не показываете, который каким-то образом все испортил.   -  person matt    schedule 30.03.2014
comment
Спасибо @matt, UIImageView создается в раскадровке, где автомакет отключен. Вы правы насчет рамок и границ. Однако, поскольку self.view расположен в (0/0), он работает. Как вы думаете, это связано с проблемой закругления углов?   -  person Hermann Klecker    schedule 30.03.2014
comment
Это не мой проект. Я просто добавляю гибкий макет для разных размеров экрана iPhone. Так что вы можете быть правы с чем-то еще .... Я рад поделиться дополнительным кодом и проверить настройки в IB/Storyboard, но я был бы признателен за любые советы о том, на что смотреть.   -  person Hermann Klecker    schedule 30.03.2014
comment
Нет, я уверен, что это не связано. :) Может быть проблема с позиционированием кадра, но на скругление это не повлияет!   -  person matt    schedule 30.03.2014
comment
Я заметил еще одно отличие на ваших снимках экрана: на втором верхняя часть сдвинута вниз, как будто панель навигации не отображается. Это может быть ПОДСКАЗКА!   -  person matt    schedule 30.03.2014


Ответы (2)


Ответ прост. Код сработал. Он добавил закругленные углы к объекту UIImageView, и maskToBounds работал хорошо.

Но фактическое отображаемое изображение меньше. Я использовал AspectFit в качестве режима, чтобы фактическое изображение не сжималось, а отображалось в исходном соотношении сторон. Из-за более длинной компоновки размеров iPhone5 изображение заполнило только часть принадлежащего ему UIImageView. Я изменил цвет фона на серый для скриншота, и теперь он становится ясным.

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

(Я обновлю этот ответ, когда это будет сделано).

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

Обновление: это то, что я наконец сделал: я удалил UIImageView из раскадровки и обработал его программно.

Не смущайтесь сложностью. Я добавил еще один вид, чтобы отбросить тень, хотя это не связано с исходным вопросом. Тень, которую я все равно хотел добавить. И оказалось, что тень CALayer и masksToBounds=YES не совсем совпадают. Вот почему я добавил обычный UIView, который находится между представлением карты и фоновым представлением.

Наконец, отображение простого прямоугольного изображения настолько утомительно, что я думаю, что просто создать подкласс UIView и отрисовать все с помощью openGL или около того непосредственно в CALayer, вероятно, было бы намного проще. :-)

Во всяком случае, это мой код:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.state = @0;

    // Create an image view to carry the image with round rects
    // and create a regular view to create the shadow.
    // Add the shadow view first so that it appears behind
    // the actual image view.

    // Explanation: We need a separate view for the shadow with the same
    // dimenstions as the imageView. This is because the imageView's image
    // is rectangular and will only be clipped to round rects when the
    // property masksToBounds is set to YES. But this setting will also
    // clip away any shadow that the imageView's layer may have.
    // Therfore we add a separate mainly empty UIView just behind the
    // UIImageview to throw the shadow.


    self.shadowV = [[UIView alloc] init];
    self.imageV = [[UIImageView alloc] initWithImage:self.image];
    [self.view addSubview:self.shadowV];
    [self.shadowV addSubview:self.imageV];

    // set the raidus and the mask to follow the rounded corners.
    [self.imageV.layer setCornerRadius:CORNER_RADIUS];
    [self.imageV.layer setMasksToBounds:YES];
    [self.imageV setContentMode:UIViewContentModeScaleAspectFit];

    // set the shadows properties
    [self.shadowV.layer setShadowColor:[UIColor blackColor].CGColor];
    [self.shadowV.layer setShadowOpacity:0.4];
    [self.shadowV.layer setShadowRadius:3.0];
    [self.shadowV.layer setShadowOffset:CGSizeMake(SHADOW_OFFSET, SHADOW_OFFSET)];
    [self.shadowV.layer setCornerRadius:CORNER_RADIUS];
    [self.shadowV setBackgroundColor:[UIColor whiteColor]];   // The view needs to have some content. Otherwise it is not displayed at all, not even its shadow.

}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    // Just to be save
    if (!self.image) {
        return;
    }

    self.imageV.image = self.image; // The image property was set by the caller.

    // Layout imageV within self.view with a margin of MARGIN
    self.imageV.frame = CGRectMake(MARGIN, MARGIN, self.view.bounds.size.width - 2 * MARGIN, self.view.bounds.size.height - 2 * MARGIN);


    // Calculate the size and position of the image and set the image view to
    // the same dimensions
    // This works under the assumption, that the image content mode is aspectFit.
    // Well, as we are doing so much of the layout manually, it would work with a number of content modes. :-)

    float imageWidth, imageHeight;
    float heightWidthRatioImageView     = self.view.frame.size.height / self.view.frame.size.width;
    float heightWidthRatioImage         = self.image.size.height / self.image.size.width;

    if (heightWidthRatioImageView > heightWidthRatioImage) {
        // The ImageView is "higher" than the image itself.
        // --> The image width is set to the imageView width and its height is scaled accordingly.
        imageWidth  = self.imageV.frame.size.width;
        imageHeight = imageWidth * heightWidthRatioImage;
    } else {
        // The ImageView is "wider" than the image itself.
        // --> The image height is set to the imageView height and its width is scaled accordingly.
        imageHeight = self.imageV.frame.size.height;
        imageWidth  = imageHeight / heightWidthRatioImage;
    }

    // Layout imageView and ShadowView accordingly.
    CGRect imageRect =CGRectMake((self.view.bounds.size.width - imageWidth) / 2,
                                 (self.view.bounds.size.height - imageHeight) / 2,
                                 imageWidth, imageHeight);
    [self.shadowV setFrame:imageRect];
    [self.imageV setFrame:CGRectMake(0.0f, 0.0f, imageWidth, imageHeight)]; // Origin is (0,0) because it overlaps its superview which just throws the shadow.

}

И вот как это наконец выглядит: введите здесь описание изображениявведите здесь описание изображения

person Hermann Klecker    schedule 30.03.2014
comment
И на самом деле, если вы посмотрите на то, что я все время говорил о макете — почему на втором снимке изображение намного ниже сверху и выше снизу — вы увидите, что эта разница была подскажите по этим строчкам! Отличная работа. - Я не решил это, хотя; Я думал о том, чтобы посоветовать вам придать изображению фоновый цвет или проверить режим содержимого, но я никогда этого не говорил. - person matt; 31.03.2014
comment
Еще раз большое спасибо. Вы подтолкнули меня в правильном направлении. На всякий случай, если кто-то еще столкнется с подобной проблемой, я дополню свой ответ окончательным кодом и снимками экрана. - person Hermann Klecker; 31.03.2014
comment
Вы даже можете отметить свой ответ через пару дней, просто чтобы показать, что проблема решена. - person matt; 31.03.2014

Проблема связана с какой-то проблемой с кодом или конфигурацией, о которой вы нам не сообщили. Доказательство: я запустил следующее, и оно отлично работает. Обратите внимание, что я создаю представление изображения в коде (чтобы избежать проблемы с автоматическим макетом) и исправил вашу путаницу с рамкой/границами, и что я пропустил ваш self.image, но ничего из этого не имеет отношения к проблеме, которую вы видите:

#define CORNER_RADIUS 18
#define MARGIN 15
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.imageV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"im"]];
    [self.view addSubview:self.imageV];
    // Layout imageV within self.view with a margin of MARGIN
    self.imageV.frame = CGRectMake(self.view.bounds.origin.x + MARGIN, self.view.bounds.origin.y + MARGIN, self.view.bounds.size.width - 2 * MARGIN, self.view.bounds.size.height - 2 * MARGIN);
    // set the raidus and the mask to follow the rounded corners.
    self.imageV.layer.cornerRadius = CORNER_RADIUS;
    self.imageV.layer.masksToBounds = YES;
}

Он отлично работает (и вы можете убедиться в этом сами). Вот скриншот 4-дюймового симулятора:

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

Поэтому проблема находится за пределами кода, который вы цитируете в своем вопросе, и не может быть проанализирована без дополнительной информации.

person matt    schedule 30.03.2014
comment
В общем, всегда делайте (когда возникают эти загадочные проблемы) то, что я делаю здесь: делайте крошечный проект только с кодом, который кажется странным, и не более того. Если, как здесь, все работает нормально, это доказывает, что проблема в другом месте. Это занимает всего минуту и ​​является ценным аналитическим инструментом. - person matt; 30.03.2014
comment
Хорошо, пока спасибо. Проблема должна быть где-то в раскадровке, где я ее не вижу. Я создал представление изображения программно, и теперь оно работает. Если речь шла только о преодолении этого, то ваш совет был полезен. Но проект от юниора/судента, и я хотел бы узнать, что на самом деле вызвало проблему. Но вы указываете в правильном направлении. Проголосуйте на данный момент, принятие последует, если не придет ответ, который еще больше сузит его. - person Hermann Klecker; 30.03.2014
comment
Есть несколько раскадровок? - person matt; 30.03.2014
comment
Есть только один. Это довольно небольшой проект. Одна из многочисленных игр в скрам-покер. Корневое представление — это контроллер представления вкладок, затем один из его навигационных контроллеров поставляется с прямым представлением коллекции, показывающим все карты. Когда карта выбрана, появляется контроллер подробного представления, отображающий эту самую карту. Вообще ничего сложного. - person Hermann Klecker; 30.03.2014
comment
Хорошо, но почему на первом снимке экрана нет места вверху для панели навигации и внизу нет места для панели вкладок, а на втором — есть? Кажется, вы достигаете этих снимков экрана двумя очень разными способами / контекстами. Это заставляет меня сомневаться в достоверности теста с вашей стороны. - person matt; 30.03.2014
comment
Хм... Я проверю насчет навигационной панели. Может быть скрыт. Два снимка экрана могут быть получены с симулированных устройств 3.5 и 4. 5 устройств показывают свободное пространство вверху и внизу экрана. Пока так и задумано. - person Hermann Klecker; 30.03.2014
comment
Для теста я просто изменил модус iPhone Simulator, повторно запустил идентичный код и сделал скриншоты. - person Hermann Klecker; 30.03.2014
comment
Наконец я нашел его. Это довольно смущает. Просто, но я просто не видел. Я опубликую ответ через минуту. - person Hermann Klecker; 31.03.2014