Possible Duplicate:
Manually drawing a gradient in iPhone apps?
Мое приложение должно отображать текст в UIView или UILabel, но фон должен быть градиентным, а не истинным UIColor. Использование графической программы для создания желаемого внешнего вида бесполезно, поскольку текст может отличаться в зависимости от данных, возвращаемых с сервера.
Кто-нибудь знает самый быстрый способ решить эту проблему? Ваши мысли очень ценятся.





Вы можете использовать Core Graphics, чтобы нарисовать градиент, как указано в ответе Майка. В качестве более подробного примера вы можете создать подкласс UIView для использования в качестве фона для вашего UILabel. В этом подклассе UIView переопределите метод drawRect: и вставьте код, подобный следующему:
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.35, // Start color
1.0, 1.0, 1.0, 0.06 }; // End color
rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGRect currentBounds = self.bounds;
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(currentContext, glossGradient, topCenter, midCenter, 0);
CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace);
}
В этом конкретном примере создается белый глянцевый градиент, который рисуется от верхней части UIView к его вертикальному центру. Вы можете настроить UIViewbackgroundColor на все, что захотите, и этот блеск будет нанесен поверх этого цвета. Вы также можете нарисовать радиальный градиент с помощью функции CGContextDrawRadialGradient.
Вам просто нужно правильно выбрать размер этого UIView и добавить свой UILabel в качестве его части, чтобы получить желаемый эффект.
РЕДАКТИРОВАТЬ (4/23/2009): по предложению St3fan я заменил фрейм представления его границами в коде. Это исправляет случай, когда источник представления не (0,0).
Вы правы, спасибо, что указали на это. С тех пор я исправил свой собственный код, но забыл, что это требует обновления. Ситуация, которая возникает у вас, - это когда исходная точка вида имеет положение Y, отличное от 0. Затем градиент отрисовывается смещением от центра по вертикали.
Можно ли это применить к UIImage или UIImageView, чтобы иметь любое изображение с градиентом?
Вы можете разместить это поверх UIImageView, чтобы добавить градиент. Для изменения содержимого изображения вам может потребоваться сначала нарисовать изображение в контексте, нарисовать градиент над ним в этом контексте, а затем сохранить контекст как новое изображение.
Можете ли вы сказать мне, как вы определяете цвета при использовании следующих компонентов: CGFloat components [8] = {1.0, 1.0, 1.0, 0.35, 1.0, 1.0, 1.0, 0.06}; Как узнать, например, что такое 1.0 и 0.35?
@Fulvio - это два цвета, представленные двумя наборами красного, зеленого, синего и альфа-компонентов. Эти компоненты нормализованы до 1,0, так что непрозрачный черный будет (0,0, 0,0, 0,0, 1,0), а непрозрачный белый будет (1,0, 1,0, 1,0, 1,0).
Как вы вызываете этот метод и / или применяете его к UIImageView?
Невозможно для UIImageView - он не вызывает drawRect.
Не забудьте добавить масштаб устройства: CGRect currentBounds = (CGRect) {0, 0, self.bounds.size.width * [UIScreen mainScreen] .scale, self.bounds.size.height * [UIScreen mainScreen] .scale ,};
Вы также можете использовать графическое изображение шириной в один пиксель в качестве градиента и установить свойство view, чтобы развернуть графику, чтобы заполнить вид (при условии, что вы думаете о простом линейном градиенте, а не о какой-то радиальной графике).
Привет, Кендалл, спасибо, чувак, ты сработал для меня. Решил это просто, поместив градиент в UIImageView и поместив поверх него динамическую метку. Спасибо всем за помощь. Тони
При таком подходе убедитесь, что у вас есть два разных градиента: один для обычных дисплеев и один для дисплеев Retina.
Одним из важных преимуществ этого решения по сравнению с кодированными решениями является то, что цветовые градиенты обычно являются свойством украшения и на самом деле не должны выражаться в коде вообще. Вот для чего нужны графические ребята. Написание кода для выражения цветов - плохое разделение логики от представления. Когда маркетинговая команда решает изменить цвета, и специалист по графике спрашивает, как это сделать, ему не понравится, когда ему говорят, что вы просто настраиваете массив цветов на CAGradientLayer в MyLabelView.m ... и он не должен. Не имеет большого значения для магазина одного человека, но для команды имеет значение.
Я согласен с Нейтом в том, что было бы хорошо позволить дизайнерам изменять активы как можно проще.
@Nate - ваш код для вашей логики должен быть отделен от вашего кода для вашей презентации. Это не означает, что ваше единственное возможное решение - иметь графический файл, и, честно говоря, для каждого растрового изображения в вашем приложении вы настраиваете себя на дополнительную работу в будущем. Код градиента всегда будет отлично выглядеть. Растровое изображение будет хорошо выглядеть только до тех пор, пока Apple снова не решит увеличить разрешение экрана.
Подумайте об использовании UIImageView для градиентов как о наилучшем способе отделения логики от представления. Это больше работы, но главное, что нужно учитывать, - это работа для людей, которые напрямую нуждаются в максимальном контроле над ней. Это не просто работа по кодированию, и это тоже важно.
То же самое для представлений с динамической высотой, например, для ячейки, высота которой зависит от того, сколько текста она должна содержать.
Зачем вам менять 50 файлов xib, если у вас есть только одно изображение градиента, которое вы меняете? Теоретически это было бы так же просто, как изменить код. Я вижу, что код для градиентов используется, когда вам по какой-то причине нужно динамически создать градиент.
Я достигаю этого в представлении с подпредставлением, которое является UIImageView. Изображение, на которое указывает ImageView, является градиентом. Затем я устанавливаю цвет фона в UIView, и у меня есть цветной градиентный вид. Затем я использую вид, как мне нужно, и все, что я рисую, будет находиться под этим видом градиента. Добавив второе представление поверх ImageView, вы можете иметь некоторые параметры, будет ли ваш рисунок ниже или выше градиента ...
Я понимаю, что это более старая ветка, но для справки в будущем:
Начиная с iPhone SDK 3.0, пользовательские градиенты можно очень легко реализовать без создания подклассов или изображений с помощью нового CAGradientLayer:
UIView *view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 100)] autorelease];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = view.bounds;
gradient.colors = [NSArray arrayWithObjects:(id)[[UIColor blackColor] CGColor], (id)[[UIColor whiteColor] CGColor], nil];
[view.layer insertSublayer:gradient atIndex:0];
Взгляните на документы CAGradientLayer. При желании вы можете указать начальную и конечную точки (если вам не нужен линейный градиент, идущий прямо сверху вниз) или даже определенные местоположения, которые соответствуют каждому из цветов.
На всякий случай, если мой комментарий попадется кому-нибудь на глаза, когда они рассматривают возможность реализации других решений, указанных выше, СДЕЛАТЬ ЭТО. Это не может быть проще (но помните, что вам нужно добавить фреймворк QuartzCore и импортировать #import <QuartzCore/QuartzCore.h> в свой класс).
Отличная работа: намного проще, чем другие решения.
Мне это нравится, но мне интересно, как это выглядит по сравнению с предварительным рендерингом изображения с градиентом. Я особенно думаю о случае ячеек табличного представления, где во время прокрутки может происходить много перерисовок.
Хорошая точка зрения. Я использовал это только как фиксированный фон для всего вида и не заметил каких-либо значительных накладных расходов. Не уверен, насколько хорошо он работает с отдельными ячейками таблицы. Хотя это должно быть легко узнать.
Кто-то может применить дополнительный эффект, например, cornerRadius. Они должны добавить сюда еще код: view.layer.masksToBounds = YES;, чтобы убедиться, что все идет гладко.
Это сработало отлично, большое спасибо!
Какой способ обеспечивает лучшую производительность? Используете CAGradientLayer или UIImageViews?
Мои эксперименты показали, что изображения с фиксированным градиентом изображения показывают лучшую производительность, чем использование CAGradientLayer.
Хм. Текст моей метки исчезает, когда я использую это решение.
Эй, это потрясающе - спасибо! («Он написал больше года спустя.») Интересно, могу ли я использовать это для ячеек табличного представления на выбранном и невыделенном фоне? Я думаю, я просто вставляю подслои в каждое из этих представлений в ячейке. Может быть. (Я предполагаю, что в выбранном состоянии уже есть градиент - хм ...!)
@Mike: Насколько велика разница в производительности? Есть ли у вас какие-то конкретные тесты / показатели, подтверждающие ваше утверждение?
@Rafael Довольно большая разница. Я написал приложение, очень похожее на почтовое приложение, и использую синий шарик с градиентной заливкой в каждой ячейке таблицы, чтобы отмечать непрочитанное сообщение. Прокрутка таблицы была значительно медленнее, чем альтернатива с заранее созданным изображением мяча. Попробуйте и убедитесь.
@HiveHicks Я обнаружил, что если я использую CAGradientLayer для UILabel, мне нужно установить backgroundColor на [UIColor clearColor] (или эквивалент)
Я пытаюсь использовать это для uitableviewcell, и градиент выходит за пределы правой части ячейки. Что я делаю неправильно?
Совет: чтобы использовать выделение (и показать другой градиент с выделением), создайте подкласс UIButton и используйте метод "- (void) setHighlighted: (BOOL) highlight {if (highlight! = Self.highlighted) {...}}". Затем я вставляю туда переключение слоев (ставим нормальный слой на ноль и выделяю на 1). Работает отлично.
У меня он работает, с градиентами, выделением (градиент на выделении тоже), закругленными углами и т. д. Вы также можете скачать код: banane.com/2012/06/01/iphone-gradient-buttons-with-high освещения
Я добавил это в свою ячейку таблицы. У меня при загрузке видно 9 строк. Когда я загружаю таблицу с помощью нажатия кнопки в основном представлении, для ее нажатия требуется добрых 10 секунд. Нулевые секунды без градиента. Почему такая задержка?
То, что нарисовано с помощью drawRect: все еще находится под этим градиентом. Просто забавный факт.
@Mike - Интересно, правильно ли вы используете deque? Разве код рисования не должен выполняться только один раз для каждой видимой ячейки и никогда больше, если вы прокручиваете, потому что он просто повторно использует старые ячейки?
Возможно, вам потребуется связать библиотеку QuartzCore: stackoverflow.com/questions/7464399/… Проверьте решение и комментарий ниже =)
прекрасный код для применения градиента. действительно полезно
Не работает для UILabel. Цвет градиента в фоновом режиме не отображается.
Есть идеи, как сделать радиальный градиент?
Похоже, это не работает как градиент для фона всего приложения. Слой не изменяется автоматически в зависимости от вида.
@MusiGenesis см. Мой ответ здесь: stackoverflow.com/a/27236831/202875
@MirkoFroehlich, пожалуйста, проверьте этот вопрос: stackoverflow.com/questions/39255885/…
один голос за простой ответ .. Очень просто и полезно, спасибо ..! Но как я могу достичь этого для текста UILabel, а не для фона ..... любая идея ...?
Примечание: Приведенные ниже результаты применимы к более старым версиям iOS, но при тестировании на iOS 13 степпинг не происходит. Не знаю, для какой версии iOS убрали степпинг.
При использовании CAGradientLayer, в отличие от CGGradient, градиент не плавный, но имеет заметные ступенчатые переходы. См.
:
Для получения более привлекательных результатов лучше использовать CGGradient.
Не могли бы вы опубликовать код, эквивалентный примеру Мирко Фрёлиха с CGGradient?
Приведенный выше код Брэда Ларсона с использованием CGGradient достаточно хорош. Я бы сделал свой комментарий как комментарий к одному из этих ответов, но у меня пока недостаточно очков.
Как вы можете сказать? Ваши градиенты оканчиваются (внизу) разными цветами.
@MattDiPasquale У меня нет под рукой кода, который я использовал для его создания, но, насколько я помню, в конечных точках использовались те же цвета. В любом случае я сомневаюсь, что это имеет значение, поскольку моя точка зрения связана с качеством градиента. В любом случае вы сможете сами воспроизвести результаты. (В то время я использовал iOS 4.x, поэтому результаты могут отличаться от iOS 5.)
Если высота вида, который вы хотите добавить градиент, мала, я думаю, CAGradientLayer - это компромисс, который вы можете себе позволить. Если высота просмотра значительна, лучше использовать CGGradient. Таким образом, маловероятно, что вы поместите изображение большей высоты в режим прокрутки.
К комментарию Мазьода, если вы обнаружите, что генерируете один и тот же градиент (или любую другую операцию рисования) много раз одним и тем же способом и это влияет на производительность, подумайте о том, чтобы сделать это только один раз, кэшируя результат в UIImage и используя это повторно. Также отлично подходит для многослойных рисунков.
Обновил свой ответ. В моих первоначальных тестах этой проблемы не было на iOS 13.
Это то, что у меня получилось - установить UIButton в IB xCode на прозрачный / прозрачный и без изображения bg.
UIColor *pinkDarkOp = [UIColor colorWithRed:0.9f green:0.53f blue:0.69f alpha:1.0];
UIColor *pinkLightOp = [UIColor colorWithRed:0.79f green:0.45f blue:0.57f alpha:1.0];
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = [[shareWordButton layer] bounds];
gradient.cornerRadius = 7;
gradient.colors = [NSArray arrayWithObjects:
(id)pinkDarkOp.CGColor,
(id)pinkLightOp.CGColor,
nil];
gradient.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0f],
[NSNumber numberWithFloat:0.7],
nil];
[[recordButton layer] insertSublayer:gradient atIndex:0];
Хорошо, изменение - теперь я создаю подкласс UIButton и использую метод выделения: "- (void) setHighlighted: (BOOL) highlight {if (highlight! = Self.highlighted) {" внутри этого, сделайте переключение слоя. работает отлично.
Причем, подробно об этом писали здесь: banane.com/2012/06/01/iphone-gradient-buttons-with-highlighting
Как можно удалить этот CAGradientLayer из представления?
Найдите его и удалите из слоя представлений кнопки, если я помню.
Ответ Мирко Фрелиха сработал для меня, за исключением случаев, когда я хотел использовать собственные цвета. Хитрость заключается в том, чтобы указать цвет пользовательского интерфейса с помощью оттенка, насыщенности и яркости вместо RGB.
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = myView.bounds;
UIColor *startColour = [UIColor colorWithHue:.580555 saturation:0.31 brightness:0.90 alpha:1.0];
UIColor *endColour = [UIColor colorWithHue:.58333 saturation:0.50 brightness:0.62 alpha:1.0];
gradient.colors = [NSArray arrayWithObjects:(id)[startColour CGColor], (id)[endColour CGColor], nil];
[myView.layer insertSublayer:gradient atIndex:0];
Чтобы получить оттенок, насыщенность и яркость цвета, используйте встроенное средство выбора цвета xcode и перейдите на вкладку HSB. В этом представлении оттенок измеряется в градусах, поэтому разделите значение на 360, чтобы получить значение, которое вы хотите ввести в код.
Я могу добавить этот CAGradientLayer, но как его удалить из myView? Я хотел бы иметь вид, как раньше, до рисования CAGradientLayer. Есть ли для этого что-нибудь?
Я бы перебирал myView.layer.sublayers до тех пор, пока вы не получили CAGradientLayer, а затем вызвал бы removeFromSuperlayer. для (CALayer * currentLayer в [подслоях self.view.layer]) {if ([currentLayer isKindOfClass: [CAGradientLayer class]]) {[currentLayer removeFromSuperlayer]; }}
Wtf, почему бы просто не сохранить слой градиента как свойство экземпляра и удалить его, когда он больше не нужен?
Я пробовал этот код, но он неправильный. Вместо того, чтобы устанавливать для currentFrame значение self.frame, следует установить значение self.bounds.