как изменить цвет фона uibutton, пока он подсвечен?

<p>в какой-то момент в моем приложении у меня есть выделенное <code>uibutton</code> (например, когда пользователь держит палец на кнопке), и мне нужно изменить цвет фона, когда кнопка подсвечена (таким образом, пока палец пользователя все еще находится на кнопке) ).</p><p>я попробовал следующее:</p><pre><code>\_button.backgroundcolor = [uicolor redcolor]; </code></pre><p>но это не работает. цвет остается прежним. я попробовал тот же кусок кода, когда кнопка не выделена, и она работает нормально. я также попытался вызвать <code>-setneedsdisplay</code> после изменения цвета, это не имело никакого эффекта.</p><p>как заставить кнопку изменить цвет фона?</p>

<p>вы можете переопределить метод <code>uibutton</code>'s <code>sethighlighted</code>.</p><p><strong>objective-c</strong></p><pre><code>- (void)sethighlighted:(bool)highlighted { [super sethighlighted:highlighted]; if (highlighted) { self.backgroundcolor = uicolorfromrgb(0x387038); } else { self.backgroundcolor = uicolorfromrgb(0x5bb75b); } } </code></pre><p><strong>swift 3.0 и swift 4.1</strong></p><pre><code>override open var ishighlighted: bool { didset { backgroundcolor = ishighlighted ? uicolor.black : uicolor.white } } </code></pre>

<p>не уверен, что этот вид решает то, что вам нужно, или соответствует вашему общему ландшафту разработки, но в первую очередь я бы попытался изменить цвет фона кнопки в событии touchdown.</p><p><strong>вариант 1:</strong></p><p>вам понадобятся два события для захвата, uicontroleventtouchdown будет для, когда пользователь нажимает кнопку. uicontroleventtouchupinside и uicontroleventtouchupoutside будут для, когда они отпустят кнопку, чтобы вернуть ее в нормальное состояние</p><pre><code>uibutton *mybutton = [uibutton buttonwithtype:uibuttontypecustom]; [mybutton setframe:cgrectmake(10.0f, 10.0f, 100.0f, 20.f)]; [mybutton setbackgroundcolor:[uicolor bluecolor]]; [mybutton settitle:@"click me:" forstate:uicontrolstatenormal]; [mybutton settitle:@"changed" forstate:uicontrolstatehighlighted]; [mybutton addtarget:self action:@selector(buttonhighlight:) forcontrolevents:uicontroleventtouchdown]; [mybutton addtarget:self action:@selector(buttonnormal:) forcontrolevents:uicontroleventtouchupinside]; </code></pre><p><strong>вариант 2:</strong></p><p>верните изображение, созданное из того цвета, который вы хотите. это также может быть категория.</p><pre><code>+ (uiimage *)imagewithcolor:(uicolor *)color { cgrect rect = cgrectmake(0.0f, 0.0f, 1.0f, 1.0f); uigraphicsbeginimagecontext(rect.size); cgcontextref context = uigraphicsgetcurrentcontext(); cgcontextsetfillcolorwithcolor(context, [color cgcolor]); cgcontextfillrect(context, rect); uiimage *image = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); return image; } </code></pre><p>а затем измените выделенное состояние кнопки:</p><pre><code>[mybutton setbackgroundimage:[self imagewithcolor:[uicolor greencolor]] forstate:uicontrolstatehighlighted]; </code></pre>

<p>нет необходимости переопределять <code>highlighted</code> как вычисляемое свойство. вы можете использовать наблюдатель свойства, чтобы вызвать изменение цвета фона:</p><pre><code>override var highlighted: bool { didset { backgroundcolor = highlighted ? uicolor.lightgraycolor() : uicolor.whitecolor() } } </code></pre><p><strong>swift 4</strong></p><pre><code>override open var ishighlighted: bool { didset { backgroundcolor = ishighlighted ? uicolor.lightgray : uicolor.white } } </code></pre>

<p>в swift вы можете переопределить метод доступа выделенного (или выбранного) свойства вместо переопределения метода sethighlighted</p><pre><code>override var highlighted: bool { get { return super.highlighted } set { if newvalue { backgroundcolor = uicolor.blackcolor() } else { backgroundcolor = uicolor.whitecolor() } super.highlighted = newvalue } } </code></pre>

<p>удобное универсальное расширение в swift:</p><pre><code>extension uibutton { private func imagewithcolor(color: uicolor) -> uiimage { let rect = cgrectmake(0.0, 0.0, 1.0, 1.0) uigraphicsbeginimagecontext(rect.size) let context = uigraphicsgetcurrentcontext() cgcontextsetfillcolorwithcolor(context, color.cgcolor) cgcontextfillrect(context, rect) let image = uigraphicsgetimagefromcurrentimagecontext() uigraphicsendimagecontext() return image } func setbackgroundcolor(color: uicolor, foruicontrolstate state: uicontrolstate) { self.setbackgroundimage(imagewithcolor(color), forstate: state) } } </code></pre><p><strong>swift 3.</strong></p><pre><code>extension uibutton { private func imagewithcolor(color: uicolor) -> uiimage? { let rect = cgrect(x: 0.0, y: 0.0, width: 1.0, height: 1.0) uigraphicsbeginimagecontext(rect.size) let context = uigraphicsgetcurrentcontext() context?.setfillcolor(color.cgcolor) context?.fill(rect) let image = uigraphicsgetimagefromcurrentimagecontext() uigraphicsendimagecontext() return image } func setbackgroundcolor(\_ color: uicolor, for state: uicontrolstate) { self.setbackgroundimage(imagewithcolor(color: color), for: state) } } </code></pre>

<p>переопределить выделенную переменную. добавление <code>@ibinspectable</code> позволяет вам редактировать подсвеченный backgroundcolor в раскадровке, что тоже неплохо.</p><pre><code>class backgroundhighlightedbutton: uibutton { @ibinspectable var highlightedbackgroundcolor :uicolor? @ibinspectable var nonhighlightedbackgroundcolor :uicolor? override var highlighted :bool { get { return super.highlighted } set { if newvalue { self.backgroundcolor = highlightedbackgroundcolor } else { self.backgroundcolor = nonhighlightedbackgroundcolor } super.highlighted = newvalue } } } </code></pre>

<p>более компактное решение (на основе <strong>@ aleksejs-mjaliks</strong> ответа):</p><p><strong>swift 3/4 +</strong>:</p><pre><code>override var ishighlighted: bool { didset { backgroundcolor = ishighlighted ? .lightgray : .white } } </code></pre><p>свифт 2:</p><pre><code>override var highlighted: bool { didset { backgroundcolor = highlighted ? uicolor.lightgraycolor() : uicolor.whitecolor() } } </code></pre><p>если вы не хотите переопределять, это обновленная версия ответа <strong>@ timur-bernikowich</strong> (<strong>swift 4.2</strong>):</p><pre><code>extension uibutton { func setbackgroundcolor(\_ color: uicolor, forstate controlstate: uicontrol.state) { let colorimage = uigraphicsimagerenderer(size: cgsize(width: 1, height: 1)).image { \_ in color.setfill() uibezierpath(rect: cgrect(x: 0, y: 0, width: 1, height: 1)).fill() } setbackgroundimage(colorimage, for: controlstate) } } </code></pre>

<p>расширение uibutton с <strong> swift 3 + </strong> синтаксисом:</p><pre><code>extension uibutton { func setbackgroundcolor(color: uicolor, forstate: uicontrolstate) { uigraphicsbeginimagecontext(cgsize(width: 1, height: 1)) uigraphicsgetcurrentcontext()!.setfillcolor(color.cgcolor) uigraphicsgetcurrentcontext()!.fill(cgrect(x: 0, y: 0, width: 1, height: 1)) let colorimage = uigraphicsgetimagefromcurrentimagecontext() uigraphicsendimagecontext() self.setbackgroundimage(colorimage, for: forstate) }} </code></pre><p>используйте это как:</p><pre><code>yourbutton.setbackgroundcolor(color: uicolor.white, forstate: .highlighted) </code></pre><p>оригинальный ответ: <a href="https://stackoverflow.com/a/30604658/3659227">https://stackoverflow.com/a/30604658/3659227</a> </p>

<p>вот подход в swift, использующий расширение uibutton для добавления ibinspectable, называемого selectedbackgroundcolor. подобно подклассу, не требуя подкласса.</p><pre><code>private var highlightedbackgroundcolorkey = 0 private var normalbackgroundcolorkey = 0 extension uibutton { @ibinspectable var highlightedbackgroundcolor: uicolor? { get { return objc\_getassociatedobject(self, &highlightedbackgroundcolorkey) as? uicolor } set(newvalue) { objc\_setassociatedobject(self, &highlightedbackgroundcolorkey, newvalue, uint(objc\_association\_retain)) } } private var normalbackgroundcolor: uicolor? { get { return objc\_getassociatedobject(self, &normalbackgroundcolorkey) as? uicolor } set(newvalue) { objc\_setassociatedobject(self, &normalbackgroundcolorkey, newvalue, uint(objc\_association\_retain)) } } override public var backgroundcolor: uicolor? { didset { if !highlighted { normalbackgroundcolor = backgroundcolor } } } override public var highlighted: bool { didset { if let highlightedbackgroundcolor = self.highlightedbackgroundcolor { if highlighted { backgroundcolor = highlightedbackgroundcolor } else { backgroundcolor = normalbackgroundcolor } } } } } </code></pre><p>надеюсь, это поможет.</p>

<p>вы можете использовать эту категорию, чтобы добавить метод <strong> setbackgroundcolor: forstate: </strong></p><p> <a href="https://github.com/damienromito/uibutton-setbackgroundcolor-forstate-">https://github.com/damienromito/uibutton-setbackgroundcolor-forstate-</a> </p>

<p>мое лучшее решение для <strong>swift 3+</strong> без подклассов.</p><pre><code>extension uibutton { func setbackgroundcolor(\_ color: uicolor, for state: uicontrolstate) { let rect = cgrect(x: 0, y: 0, width: 1, height: 1) uigraphicsbeginimagecontext(rect.size) color.setfill() uirectfill(rect) let colorimage = uigraphicsgetimagefromcurrentimagecontext() uigraphicsendimagecontext() setbackgroundimage(colorimage, for: state) } } </code></pre><p>с этим расширением легко управлять цветами для разных состояний, и оно автоматически затухает в обычном цвете, если выделенный цвет не предусмотрен.</p><pre><code>button.setbackgroundcolor(.red, for: .normal) </code></pre>

<p>создайте подкласс uibutton и добавьте проверяемые свойства для удобного использования (написано в swift 3.0):</p><pre><code>final class selectablebackgroundbutton: uibutton { private struct constants { static let animationduration: nstimeinterval = 0.1 } @ibinspectable var animatedcolorchange: bool = true @ibinspectable var selectedbgcolor: uicolor = uicolor.blackcolor().colorwithalphacomponent(0.2) @ibinspectable var normalbgcolor: uicolor = uicolor.clearcolor() override var selected: bool { didset { if animatedcolorchange { uiview.animatewithduration(constants.animationduration) { self.backgroundcolor = self.selected ? self.selectedbgcolor : self.normalbgcolor } } else { self.backgroundcolor = selected ? selectedbgcolor : normalbgcolor } } } override var highlighted: bool { didset { if animatedcolorchange { uiview.animatewithduration(constants.animationduration) { self.backgroundcolor = self.highlighted ? self.selectedbgcolor : self.normalbgcolor } } else { self.backgroundcolor = highlighted ? selectedbgcolor : normalbgcolor } } } } </code></pre>

<p>попробуй это !!!!</p><p>для события toucheddown установите один цвет, а для touchupinside - другой.</p><pre><code>- (ibaction)toucheddown:(id)sender { nslog(@"touched down"); btn1.backgroundcolor=[uicolor redcolor]; } - (ibaction)touchupinside:(id)sender { nslog(@"touchupinside"); btn1.backgroundcolor=[uicolor whitecolor]; } </code></pre>

<p>обновление:</p><p>используйте библиотеку <a href="https://github.com/acani/uibuttonbackgroundcolor">ibuttonbackgroundcolor</a> swift.</p><p>old:</p><p>используйте помощники ниже, чтобы создать изображение размером 1 px x 1 px с цветом заливки в оттенках серого:</p><pre><code>uiimage *image = acutilingimagegray(248/255.0, 1); </code></pre><p>или цвет заливки rgb:</p><pre><code>uiimage *image = acutilingimagergb(253/255.0, 123/255.0, 43/255.0, 1); </code></pre><p>затем используйте это <code>image</code>, чтобы установить фоновое изображение кнопки:</p><pre><code>[button setbackgroundimage:image forstate:uicontrolstatenormal]; </code></pre><h3>помощники</h3><pre><code>#pragma mark - helpers uiimage *acutilingimagegray(cgfloat gray, cgfloat alpha) { return acutilingimage(alpha, ^(cgcontextref context) { cgcontextsetgrayfillcolor(context, gray, alpha); }); } uiimage *acutilingimagergb(cgfloat red, cgfloat green, cgfloat blue, cgfloat alpha) { return acutilingimage(alpha, ^(cgcontextref context) { cgcontextsetrgbfillcolor(context, red, green, blue, alpha); }); } uiimage *acutilingimage(cgfloat alpha, void (^setfillcolor)(cgcontextref context)) { cgrect rect = cgrectmake(0, 0, 0.5, 0.5); uigraphicsbeginimagecontextwithoptions(rect.size, alpha == 1, 0); cgcontextref context = uigraphicsgetcurrentcontext(); setfillcolor(context); cgcontextfillrect(context, rect); uiimage *image = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); return image; } </code></pre><p>примечание: <code>acu</code> - это префикс класса моей статической библиотеки cocoa touch под названием acani utilities, где ac - для acani, а u - для utilities.</p>

<p>вы можете создать подкласс uibutton и создать nice forstate.</p><p><strong>colourbutton.h</strong></p><pre><code>#import <uikit/uikit.h> @interface colourbutton : uibutton -(void)setbackgroundcolor:(uicolor *)backgroundcolor forstate:(uicontrolstate)state; @end </code></pre><p><strong>colourbutton.m</strong></p><pre><code>#import "colourbutton.h" @implementation colourbutton { nsmutabledictionary *colours; } -(id)initwithcoder:(nscoder *)adecoder { self = [super initwithcoder:adecoder]; // if colours does not exist if(!colours) { colours = [nsmutabledictionary new]; // the dictionary is used to store the colour, the key is a text version of the enum colours[[nsstring stringwithformat:@"%lu", uicontrolstatenormal]] = (uicolor*)self.backgroundcolor; // store the original background colour } return self; } -(void)setbackgroundcolor:(uicolor *)backgroundcolor forstate:(uicontrolstate)state { // if it is normal then set the standard background here if(state & uicontrolstatenormal) { [super setbackgroundcolor:backgroundcolor]; } // store the background colour for that state colours[[nsstring stringwithformat:@"%lu", state]]= backgroundcolor; } -(void)sethighlighted:(bool)highlighted { // do original highlight [super sethighlighted:highlighted]; // highlight with new colour or replace with orignial if (highlighted && colours[[nsstring stringwithformat:@"%lu", uicontrolstatehighlighted]]) { self.backgroundcolor = colours[[nsstring stringwithformat:@"%lu", uicontrolstatehighlighted]]; } else { self.backgroundcolor = colours[[nsstring stringwithformat:@"%lu", uicontrolstatenormal]]; } } -(void)setselected:(bool)selected { // do original selected [super setselected:selected]; // select with new colour or replace with orignial if (selected && colours[[nsstring stringwithformat:@"%lu", uicontrolstateselected]]) { self.backgroundcolor = colours[[nsstring stringwithformat:@"%lu", uicontrolstateselected]]; } else { self.backgroundcolor = colours[[nsstring stringwithformat:@"%lu", uicontrolstatenormal]]; } } @end </code></pre><p><strong>примечания</strong> (это пример, я знаю, что есть проблемы, а вот некоторые)</p><p>я использовал nsmutabledictionay для хранения uicolor для каждого состояния, я должен сделать неприятное преобразование текста для ключа, поскольку uicontrolstate не является хорошим прямым int. если это где вы могли бы начать массив с таким количеством объектов и использовать состояние в качестве индекса.</p><p>из-за этого у многих возникают проблемы, например, выбранная и отключенная кнопка, необходима дополнительная логика.</p><p>другая проблема - если вы пытаетесь установить несколько цветов одновременно, я не пробовал с кнопкой, но если вы можете сделать это, она может не работать</p><pre><code> [btn setbackgroundcolor:colour forstate:uicontrolstateselected & uicontrolstatehighlighted]; </code></pre><p>я предположил, что это storyboard, нет init, initwithframe, поэтому добавьте их, если они вам нужны.</p>

<p>я открыл исходный код подкласса uibutton, <a href="https://github.com/stunner/stacontrols/blob/master/stacontrols/stacontrols/button/stabutton.m">stabutton</a> , чтобы заполнить эту пробел в функциональности. доступно под лицензией mit. работает для ios 7+ (я не тестировал со старыми версиями ios).</p>

<p>чтобы решить эту проблему, я создал категорию для обработки <code>backgroundcolor</code> состояний с <code>uibuttons</code>:<br> <a href="https://github.com/gabrielmassana/buttonbackgroundcolor-ios/tree/master/buttonbackgroundcolor-ios">buttonbackgroundcolor-ios</a> </p><p>вы можете установить категорию как <a href="https://github.com/gabrielmassana/buttonbackgroundcolor-ios/blob/master/readme.md">pod</a> .</p><p>легко использовать с <strong> objective-c </strong></p><pre><code>@property (nonatomic, strong) uibutton *mybutton; ... [self.mybutton bbc\_backgroundcolornormal:[uicolor redcolor] backgroundcolorselected:[uicolor bluecolor]]; </code></pre><p>еще проще в использовании с <strong> swift </strong>:</p><pre><code>import buttonbackgroundcolor ... let mybutton:uibutton = uibutton(type:.custom) mybutton.bbc\_backgroundcolornormal(uicolor.redcolor(), backgroundcolorselected: uicolor.bluecolor()) </code></pre><p>я рекомендую вам импортировать пакет с:</p><pre><code>platform :ios, '8.0' use\_frameworks! pod 'buttonbackgroundcolor', '~> 1.0' </code></pre><p>использование use\_frameworks! в вашем podfile упрощает использование ваших модулей с swift и target-c.</p><p><strong>важно</strong></p><p> <a href="https://somethingaboutios.wordpress.com/2016/02/09/uibutton-backgroundcolor-for-uicontrolstateselected/"><strong> я также написал сообщение в блоге с дополнительной информацией. </strong></a> </p>

<p>попробуйте это, если у вас есть изображение:</p><pre><code>-(void)setbackgroundimage:(uiimage *)image forstate:(uicontrolstate)state; </code></pre><p>или посмотрите, достаточно ли вам <code>showstouchwhenhighlighted</code>.</p>

<p>использовать <a href="https://github.com/swordray/uibuttonsetbackgroundcolorforstate">https://github.com/swordray/uibuttonsetbackgroundcolorforstate</a> </p><p>добавить в podfile, используя cocoapods</p><pre class="lang-ruby prettyprint-override"><code>pod "uibuttonsetbackgroundcolorforstate" </code></pre><p><strong> swift </strong></p><pre class="lang-swift prettyprint-override"><code>button.setbackgroundcolor(.red, forstate: .highlighted) </code></pre><p><strong> objective-c </strong></p><pre class="lang-m prettyprint-override"><code>[button setbackgroundcolor:[uicolor redcolor] forstate:uicontrolstatehighlighted]; </code></pre>

<pre><code>class custombutton: uibutton { override var ishighlighted: bool { didset { if (ishighlighted) { alpha = 0.5 } else { alpha = 1 } } } } </code></pre>

<p> <br><code>private var highlightedbackgroundcolors = [uibutton:uicolor]() private var unhighlightedbackgroundcolors = [uibutton:uicolor]() extension uibutton { @ibinspectable var highlightedbackgroundcolor: uicolor? { get { return highlightedbackgroundcolors[self] } set { highlightedbackgroundcolors[self] = newvalue } } override open var backgroundcolor: uicolor? { get { return super.backgroundcolor } set { unhighlightedbackgroundcolors[self] = newvalue super.backgroundcolor = newvalue } } override open var ishighlighted: bool { get { return super.ishighlighted } set { if highlightedbackgroundcolor != nil { super.backgroundcolor = newvalue ? highlightedbackgroundcolor : unhighlightedbackgroundcolors[self] } super.ishighlighted = newvalue } } } </code></p><pre></pre>

<p>вот код в swift, который нужно выбрать для состояния кнопки:</p><pre><code>func imagewithcolor(color:uicolor) -> uiimage { let rect:cgrect = cgrectmake(0.0, 0.0, 1.0, 1.0) uigraphicsbeginimagecontext(rect.size) let context:cgcontextref = uigraphicsgetcurrentcontext()! cgcontextsetfillcolorwithcolor(context, color.cgcolor) cgcontextfillrect(context, rect) let image:uiimage = uigraphicsgetimagefromcurrentimagecontext(); return image; } </code></pre><p>пример:</p><pre><code> self.button.setimage(self.imagewithcolor(uicolor.blackcolor()), forstate: .highlighted) </code></pre>

<p>ниже расширение <code>uiiimage</code> сгенерирует объект изображения с указанным параметром цвета.</p><pre><code>extension uiimage { static func imagewithcolor(tintcolor: uicolor) -> uiimage { let rect = cgrect(x: 0, y: 0, width: 1, height: 1) uigraphicsbeginimagecontextwithoptions(rect.size, false, 0) tintcolor.setfill() uirectfill(rect) let image: uiimage = uigraphicsgetimagefromcurrentimagecontext()! uigraphicsendimagecontext() return image } } </code></pre><p>пример использования кнопки может быть применен для объекта кнопки как:</p><pre><code>setupbutton.setbackgroundimage(uiimage.imagewithcolor(tintcolor: uicolor(displayp3red: 232/255, green: 130/255, blue: 121/255, alpha: 1.0)), for: uicontrolstate.highlighted) setupbutton.setbackgroundimage(uiimage.imagewithcolor(tintcolor: uicolor(displayp3red: 255/255, green: 194/255, blue: 190/255, alpha: 1.0)), for: uicontrolstate.normal) </code></pre>

<p>попробуйте <code>tintcolor</code>:</p><pre><code>\_button.tintcolor = [uicolor redcolor]; </code></pre>

<p>свифт 3:</p><pre><code>extension uibutton { private func imagewithcolor(color: uicolor) -> uiimage { let rect = cgrect(x:0.0,y:0.0,width: 1.0,height: 1.0) uigraphicsbeginimagecontext(rect.size) let context = uigraphicsgetcurrentcontext() context!.setfillcolor(color.cgcolor) context!.fill(rect) let image = uigraphicsgetimagefromcurrentimagecontext() uigraphicsendimagecontext() return image! } func setbackgroundcolor(color: uicolor, foruicontrolstate state: uicontrolstate) { self.setbackgroundimage(imagewithcolor(color: color), for: state) } } </code></pre>

<p>на раскадровке ...</p><p>вы можете изменить настройки для отдельных состояний uibutton. например, выберите "выбрано", и затем вы можете изменить цвет текста для этого состояния.</p><p>чтобы изменить фон при выделении кнопки uib:</p><ol> <li>выберите нужную кнопку в раскадровке.</li> <li>выберите желаемое состояние конфигурации. для вашего случая выберите "выделено". <a href="https://i.stack.imgur.com/jxdcs.png"><img src="https://i.stack.imgur.com/jxdcs.png" alt="how to change the state configuration in storyboard."></a> </li> <li>изменить цвет фона. теперь вы можете перейти к другим состояниям с помощью шага 2 и указать цвет фона для этого состояния. <a href="https://i.stack.imgur.com/giaig.png"><img src="https://i.stack.imgur.com/giaig.png" alt="how to change the background color in storyboard."></a> </li> </ol>

<p>если вы не будете переопределять, просто установите два действия touchdown touchupinside</p>