UIImage и resizableImageWithCapInsets

Original author: John Muchow
  • Translation
Недавно я начал писать небольшой пример, чтобы лучше изучить iOS 5 Appearance API и кастомизацию UINavigationBar. Цель была в том, чтобы добавить собственный фон, заголовок и текст в панель навигации. Когда я его закончил, я решил улучшать кнопки в панели навигации используя тот же Appearance API.
Пока я погружался в кастомизацию кнопок, я открыл для себя метод UIImage появившийся в iOS 5, resizableImageWithCapInsets. Я решил отвлечься от первоначальной идеи издеваться над панелью навигации, чтобы понять, как работает установка фиксированных границ.
(Прим. переводчика — я не нашел перевода лучше, одолжите?)
Этот пост посвящен тому, что я изучил

Установка границ для UIButton


Как написано в документации, resizableImageWithCapInsets добавляет фиксированные границы к изображению, и когда оно резайзится или масштабируется, эти границы не изменяются. Лучше всего это можно понять из примера. Давайте представим, что я хочу, чтобы все кнопки в моем интерфейсе выглядели одинаково: градиент с белой границей. Ниже представлено изображение для примеров к этому посту (изображение на сером фоне, чтобы лучше выделить белую границу):

В зависимости от контекста использования, кнопка может появляться где угодно, и размер ее может изменяться. Обычно используется следующий код для создания кнопки с фоновым изображением:
UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(80, 130, 160, 44)];  
[button setTitle:@"Test Button" forState:UIControlStateNormal];
// Картинка без фиксированных границ
UIImage *buttonImage = [UIImage imageNamed:@"blueButton"];
[button addTarget:self action:@selector(buttonPressed:) forControlEvents: UIControlEventTouchUpInside];        
[button setBackgroundImage:buttonImage forState:UIControlStateNormal];
[[self view] addSubview:button];


Как можно увидеть, кнопка растянута во всех направляниях. Теперь изменим код, включив фиксированные границы. Но прежде, давайте посмотрим сигнатуру данного метода:
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets

Заглянув чуть дальше, обнаружим, что UIEdgeInserts определяется как структура:
typedef struct {
   CGFloat top, left, bottom, right;
} UIEdgeInsets;


UIEdgeInsets — это структура, которая определяет float-значения для каждой фиксированной границы: верхняя, левая, нижняя и правая области изображения. Чтобы применить это к нашей кнопки, нужно сделать следующее:
// Изображение с установленными границами
UIImage *buttonImage = [[UIImage imageNamed:@"blueButton"]  
   resizableImageWithCapInsets:UIEdgeInsetsMake(0, 16, 0, 16)];

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


Cap Insets with UIBarButtonItem


Мы можем использовать то же самое изображение для кнопки в панели навигации. Без задания границ, кнопка выглядит вот так:

Код ниже демонстрирует создание кнопки с фиксированными 12 пикселями изображения по всей рамке:
UIImage *backButton = [[UIImage imageNamed:@"blueButton"]  
   resizableImageWithCapInsets:UIEdgeInsetsMake(12, 12, 12, 12)];

Окончательный результат:


Прим. переводчика — использование данной технологии аналогично использованию техники 9-patch в Android, за исключением того, что здесь не требуется заранее готовить изображение.
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 5

    0
    Имхо, 9-patch удобнее и нагляднее. И для замены кнопки в 9-patch не нужно править код.
      0
      9-patch, iOS — я что-то пропустил?
        +1
        Пардон, плохо гуглиться с утра.
        По сабжу, любая 3rd-party либа всегда будет 3rd-party, а когда есть нативные способы — это круто.
      0
      Есть метод stretchableImageWithLeftCapWidth:topCapHeight:, доступный аж с iOS 2.0.

      Позволяет делать кнопки примерно так:

      - (UIButton*) stretchableButton
      {
      UIImage* backgroundImageNormal = [[UIImage imageNamed:@"navigation_button.png"] stretchableImageWithLeftCapWidth:18 topCapHeight:0];
      UIImage* backgroundImageHighlighted = [[UIImage imageNamed:@"navigation_button.png"] stretchableImageWithLeftCapWidth:18 topCapHeight:0];

      UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
      [button setImage:normalImage forState:UIControlStateNormal];
      [button setImage:highlightedImage forState:UIControlStateHighlighted];
      [button setBackgroundImage:backgroundImageNormal forState:UIControlStateNormal];
      [button setBackgroundImage:backgroundImageHighlighted forState:UIControlStateHighlighted];
      [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
      button.titleLabel.font = [UIFont boldSystemFontOfSize:12.0];
      [button setTitleEdgeInsets:UIEdgeInsetsMake(0, 10, 0, 10)];

      button.frame = CGRectMake(X, Y, W, backgroundImageNormal.size.height);

      return button;
      }
        0
        Да, но проблема в том, что он depricated в iOS 5.0 и выше:

        stretchableImageWithLeftCapWidth:topCapHeight:
        Creates and returns a new image object with the specified cap values. (Deprecated in iOS 5.0. Deprecated. Use the resizableImageWithCapInsets: instead, specifying cap insets such that the interior is a 1x1 area.)

      Only users with full accounts can post comments. Log in, please.