масштабировать изображение в UIButton до AspectFit?

97

Я хочу добавить изображение в UIButton, а также хочу масштабировать свое изображение, чтобы оно соответствовало UIButton (уменьшить изображение). Пожалуйста, покажите мне, как это сделать.

Это то, что я пробовал, но это не работает:

  • Добавление изображения на кнопку и использование setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Делаем «растягивающее изображение»:
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];
КОНГ
источник
Я думаю, что это поведение было изменено по умолчанию в прошивке 4.0 и выше.
Шаун Будрам
1
См. Решение на stackoverflow.com/a/28205566/481207 .
Мэтт

Ответы:

28

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

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

UIImage + Extra.h

@interface UIImage (Extras)
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;
@end;

UIImage + Extra.m

@implementation UIImage (Extras)

- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize {

UIImage *sourceImage = self;
UIImage *newImage = nil;

CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;

CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;

CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;

CGPoint thumbnailPoint = CGPointMake(0.0,0.0);

if (!CGSizeEqualToSize(imageSize, targetSize)) {

        CGFloat widthFactor = targetWidth / width;
        CGFloat heightFactor = targetHeight / height;

        if (widthFactor < heightFactor) 
                scaleFactor = widthFactor;
        else
                scaleFactor = heightFactor;

        scaledWidth  = width * scaleFactor;
        scaledHeight = height * scaleFactor;

        // center the image

        if (widthFactor < heightFactor) {
                thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 
        } else if (widthFactor > heightFactor) {
                thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
        }
}


// this is actually the interesting part:

UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0);

CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width  = scaledWidth;
thumbnailRect.size.height = scaledHeight;

[sourceImage drawInRect:thumbnailRect];

newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

if(newImage == nil) NSLog(@"could not scale image");


return newImage ;
}

@end

Вы можете использовать его до нужного размера. Подобно :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];
gcamp
источник
Спасибо за ответ, Gcamp. У меня был метод изменения размера по соотношению. Но я все еще пытаюсь найти способ сказать UIButton сделать это за меня. Мое изображение загружено из Интернета, поэтому я не могу изменить его размер во время компиляции. Кстати, большое спасибо за ваш ответ.
KONG
2
Поскольку изображение помещается в CALayer, визуализируется и кэшируется Quartz, производительность не должна ухудшаться, если вы поместите его туда в полном размере. В любом случае вы изменяете размер ~ 1 раз. Ответ gcamp гораздо важнее, если вы постоянно меняете размер кнопки или выполняете другие действия, которые заставят Quartz перерисовать слой изображения.
Бен Готоу
похоже качество изображения ухудшилось. Тестирую на iphone 6 plus. Это правда? У меня тоже 3х изображение.
Khant Thu Linn
Да, это довольно старый код. Это было UIGraphicsBeginImageContextвместо UIGraphicsBeginImageContextWithOptions. Просто исправил.
gcamp
да, но во многих случаях это не имеет значения, если вы потеряете несколько циклов, так что нет смысла заправлять барана
Раду Симионеску
204

У меня такая же проблема. Просто установите ContentMode для ImageView, который находится внутри UIButton.

[[self.itemImageButton imageView] setContentMode: UIViewContentModeScaleAspectFit];
[self.itemImageButton setImage:[UIImage imageNamed:stretchImage] forState:UIControlStateNormal];

Надеюсь это поможет.

Дэйв
источник
14
Убедитесь, что вы устанавливаете imageView . Я также немного не заметил, что я все еще использую backgroundImageView, и он не работал для этого.
Alexandre Gomes
2
Кажется, у этого метода есть проблемы, когда состояние кнопки «подсвечено». Изображение вернется в режим заливки. Любая идея?
Юаньфэй Чжу
У меня это не работает. Однако я заставляю его работать, используя [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stretchImage] forState: UIControlStateNormal];
Микки
3
Это сработало для меня. Я установил режим содержимого, как указано выше. Однако вам также необходимо установить такое же изображение выделенного состояния, чтобы изображение не возвращалось в «режим заливки». Например, [imageButton setImage: image forState: UIControlStateHighlighted];
Кристофер
1
Вы можете сделать это в Интерфейсном imageView.contentModeNumber1
Разработчике, указав
108

Ни один из ответов здесь не помог мне, я решил проблему с помощью следующего кода:

button.contentMode = UIViewContentModeScaleToFill;
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;

Вы также можете сделать это в Интерфейсном Разработчике.

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

Nalexn
источник
5
Это не дает вам подходящего поведения, как того требует OP.
Ортвин Генц,
3
@OrtwinGentz ​​вы можете выбрать режим и установить Aspect fitвместо scale to fill.
Даниэль
55

Самый простой способ программно установить UIButton imageView в режиме соотношения сторон :

Swift

button.contentHorizontalAlignment = .fill
button.contentVerticalAlignment = .fill
button.imageView?.contentMode = .scaleAspectFit

Цель-C

button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill;
button.contentVerticalAlignment = UIControlContentVerticalAlignmentFill;
button.imageView.contentMode = UIViewContentModeScaleAspectFit;

Примечание: вы можете изменить .scaleAspectFit (UIViewContentModeScaleAspectFit) на .scaleAspectFill (UIViewContentModeScaleAspectFill), чтобы установить режим заполнения аспекта

Танги Г.
источник
20

У меня были проблемы с тем, что изображение не менялось пропорционально, поэтому я исправил его с помощью вставок по краям.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);
ниндзянин
источник
16

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

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

Capikaw
источник
14

Расширяя ответ Дейва, вы можете установить все contentModeкнопки imageViewв IB, без какого-либо кода, используя атрибуты времени выполнения:

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

  • 1означает UIViewContentModeScaleAspectFit,
  • 2будет значить UIViewContentModeScaleAspectFill.
Ортвин Генц
источник
8

Если вы просто хотите уменьшить изображение кнопки:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);
Тюльб
источник
Это должно быть yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
sdsykes
Не пробовал с .imageView. Работает без него неплохо.
Tulleb 08
6

1 - очистить текст кнопки по умолчанию (важно)

2 - установить выравнивание как изображение

3 - установить режим содержимого как изображение

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

Хамид Реза Ансари
источник
Хороший ответ, брат ... мне очень помог. Благодарность!
BharathRao
5

У меня есть метод, который сделает это за меня. Метод принимает UIButtonи подгоняет формат изображения.

-(void)makeImageAspectFitForButton:(UIButton*)button{
    button.imageView.contentMode=UIViewContentModeScaleAspectFit;
    button.contentHorizontalAlignment=UIControlContentHorizontalAlignmentFill;
    button.contentVerticalAlignment=UIControlContentVerticalAlignmentFill;
}
Абедалкарим Омрейх
источник
4

Лучшее решение - использовать Auto Layout . Опустив Content Приоритет сжатия сопротивления из моих UIButtonи установить изображение (не Фоновое изображение ) с помощью Interface Builder . После этого я добавил пару ограничений, которые определяют размер моей кнопки (довольно сложно в моем случае), и это сработало как шарм.

Рудольф Адамкович
источник
У меня это сработало, но только если я выбрал «Фоновое изображение», а не фактическое изображение. Все, что работает! Это сводило меня с ума.
Энди,
Под Xcode 6.2 это сработало для меня, но, как сказал @AndrewHeinlein, использовалBackground Image
RoLYroLLs
3

убедитесь, что вы установили для изображения свойство Image, но не значение Background

Андрей
источник
2

Фоновое изображение можно довольно легко настроить для масштабирования заливки сторон. Просто нужно сделать что-то вроде этого в подклассе UIButton:

- (CGRect)backgroundRectForBounds:(CGRect)bounds
{
    // you'll need the original size of the image, you 
    // can save it from setBackgroundImage:forControlState
    return CGRectFitToFillRect(__original_image_frame_size__, bounds);
}

// Utility function, can be saved elsewhere
CGRect CGRectFitToFillRect( CGRect inRect, CGRect maxRect )
{
    CGFloat origRes = inRect.size.width / inRect.size.height;
    CGFloat newRes = maxRect.size.width / maxRect.size.height;

    CGRect retRect = maxRect;

    if (newRes < origRes)
    {
        retRect.size.width = inRect.size.width * maxRect.size.height / inRect.size.height;
        retRect.origin.x = roundf((maxRect.size.width - retRect.size.width) / 2);
    }
    else
    {
        retRect.size.height = inRect.size.height * maxRect.size.width / inRect.size.width;
        retRect.origin.y = roundf((maxRect.size.height - retRect.size.height) / 2);
    }

    return retRect;
}
Энди Поес
источник
Разве это невозможно без подкласса?
Юлиан
Этот ответ был специально для backgroundImage. Для основного изображения вы можете обезьянничать с файлом imageEdgeInsets.
Энди
Я знаю и хотел, чтобы этого можно было добиться без подкласса.
Юлиан
Насколько мне известно, вы не можете настроить backgroundImage без создания подклассов.
Энди
1

Swift 5.0

 myButton2.contentMode = .scaleAspectFit
 myButton2.contentHorizontalAlignment = .fill
 myButton2.contentVerticalAlignment = .fill
Касим Мирза
источник
0

Для Xamarin.iOS (C #):

    myButton.VerticalAlignment = UIControlContentVerticalAlignment.Fill;
    myButton.HorizontalAlignment = UIControlContentHorizontalAlignment.Fill;
    myButton.ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;
Мацей
источник
-1

Вам просто нужно установить режим содержимого UIButton imageview для трех событий. -

[cell.button setImage:[UIImage imageWithData:data] forState:UIControlStateNormal];

[cell.button setImage:[UIImage imageWithData:data] forState:UIControlStateHighlighted];

[cell.imgIcon setImage:[UIImage imageWithData:data] forState:UIControlStateSelected];

У нас есть код для трех событий bcoz при выделении или выборе, если размер кнопки - КВАДРАТ, а размер изображения - прямоугольник, тогда оно будет показывать квадратное изображение во время выделения или выбора.

Я уверен, что это сработает для вас.

ruyamonis346
источник
Вы не устанавливаете режим содержимого, вы устанавливаете изображение. И это не события, это состояния. Вы устраиваете большой беспорядок. Это совершенно не связано с вопросом.
manecosta 07