Görüntüyü bir UIButton'da AspectFit'e ölçekle?


98

Bir UIButton'a bir resim eklemek ve ayrıca resmimi UIButton'a sığacak şekilde ölçeklemek istiyorum (resmi küçültmek). Lütfen bana nasıl yapılacağını göster.

Denediğim buydu ama işe yaramıyor:

  • Düğmeye resim eklemek ve kullanmak setContentMode:
[self.itemImageButton setImage:stretchImage forState:UIControlStateNormal];
[self.itemImageButton setContentMode:UIViewContentModeScaleAspectFit];
  • Bir "uzatılmış görüntü" oluşturma:
UIImage *stretchImage = [updatedItem.thumbnail stretchableImageWithLeftCapWidth:0 topCapHeight:0];

Bunun bellenim 4.0 ve sonraki sürümlerde varsayılan davranış olarak değiştirildiğini düşünüyorum.
Shaun Budhram

Yanıtlar:


28

Bir görüntüyü gerçekten ölçeklemek istiyorsanız yapın, ancak kullanmadan önce yeniden boyutlandırmalısınız. Çalışma zamanında yeniden boyutlandırmak sadece CPU döngülerini kaybedecektir.

Bu, bir resmi ölçeklemek için kullandığım kategori:

UIImage + Extra.h

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

UIImage + Ekstra.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

İstediğiniz boyutta kullanabilirsiniz. Sevmek :

[self.itemImageButton setImage:[stretchImage imageByScalingProportionallyToSize:CGSizeMake(20,20)]];

Cevabın için teşekkürler, Gcamp. Orana göre yeniden boyutlandırmak için bir yöntemim vardı. Ama yine de UIButton'a bunu benim için yapmasını söylemenin bir yolunu bulmaya çalışıyorum. Resmim İnternetten yüklendi, bu yüzden derleme zamanında yeniden boyutlandıramıyorum. BTW, cevabınız için çok teşekkür ederim.
KONG

2
Görüntü bir CALayer içine yerleştirildiği, işlendiği ve Quartz tarafından önbelleğe alındığı için, oraya tam boyutta yerleştirirseniz performans daha da kötü olmamalıdır. Her iki durumda da ~ 1 kez yeniden boyutlandırıyorsunuz. Düğmeyi sürekli olarak yeniden boyutlandırıyorsanız veya Quartz'ı görüntü katmanını yeniden çizmesi için tetikleyecek başka şeyler yapıyorsanız gcamp'ın cevabı çok daha önemlidir.
Ben Gotow

görüntü kalitesi düşmüş gibi görünüyor. iphone 6 plus üzerinde test ediyorum. Bu doğru mu? Ayrıca 3x resmim var.
Khant Thu Linn

Evet olacak, bu kod oldukça eski. Öyleydi UIGraphicsBeginImageContextyerine UIGraphicsBeginImageContextWithOptions. Sadece düzelttim.
gcamp

evet ama çoğu durumda birkaç döngü kaybedip kaybetmediğiniz önemli değil, bu yüzden koçu doldurmanın bir anlamı yok
Radu Simionescu

204

Ben de aynı sorunu yaşadım. UIButton'un içindeki ImageView'un ContentMode'unu ayarlamanız yeterlidir.

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

Bu yardımcı olur umarım.


14
İmageView'u ayarladığınızdan emin olun . Ayrıca, bir süreliğine, hala backgroundImageView'ı kullandığımı ve bunun için çalışmadığını fark edemedim.
Alexandre Gomes

2
Düğme durumu 'vurgulandığında' bu yöntemin bazı sorunları var gibi görünüyor. Görüntü, doldurma moduna geri dönecektir. Herhangi bir fikir?
Yuanfei Zhu

Benim için çalışmıyor. Ancak, [self.itemImageButton setbackgroundImage: [UIImage imageNamed: stretchImage] forState: UIControlStateNormal];
Mickey

3
Bu benim için çalıştı. İçerik modunu yukarıdaki gibi ayarlıyorum. Bununla birlikte, görüntünün "doldurma moduna" geri dönmesini önlemek için vurgulanan durumun aynı görüntüsünü de ayarlamanız gerekir. Örneğin, [imageButton setImage: image forState: UIControlStateHighlighted];
Christopher

1
Bunu Arayüz Oluşturucu'da anahtar yolu imageView.contentMode, tür Numberve değerle yapabilirsiniz1
bendytree

111

Buradaki cevapların hiçbiri benim için gerçekten işe yaramadı, sorunu aşağıdaki kodla çözdüm:

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

Bunu Interface Builder'da da yapabilirsiniz.

görüntü açıklamasını buraya girin


5
Bu size OP tarafından istendiği gibi görünüm uyumu davranışı vermez .
Ortwin Gentz

4
@OrtwinGentz ​​modu seçip Aspect fityerine ayarlayabilirsiniz scale to fill.
Daniel

56

Görünüme uydurma modunda bir UIButton imageView'i programlı olarak ayarlamanın en kolay yolu :

Swift

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

Amaç-C

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

Not: En boy doldurma modunu ayarlamak için .scaleAspectFit (UIViewContentModeScaleAspectFit) öğesini .scaleAspectFill (UIViewContentModeScaleAspectFill) olarak değiştirebilirsiniz.


20

Resmin orantılı olarak yeniden boyutlandırılamamasıyla ilgili sorunlar yaşadım, bu yüzden onu düzeltme şeklim kenar girintileri kullanmaktı.

fooButton.contentEdgeInsets = UIEdgeInsetsMake(10, 15, 10, 15);

16

Bu artık IB'nin UIButton özellikleri aracılığıyla yapılabilir. Anahtar, resminizi arka plan olarak ayarlamaktır, aksi takdirde çalışmaz.

görüntü açıklamasını buraya girin


14

Dave'in cevabını genişleterek, Runtime Niteliklerini kullanarak herhangi bir kod olmadan contentModedüğmenin imageViewtümünü IB'de ayarlayabilirsiniz :

görüntü açıklamasını buraya girin

  • 1anlamı UIViewContentModeScaleAspectFit,
  • 2anlamına gelir UIViewContentModeScaleAspectFill.

8

Yalnızca düğme resminizi küçültmek istiyorsanız:

yourButton.contentMode = UIViewContentModeScaleAspectFit;
yourButton.imageEdgeInsets = UIEdgeInsetsMake(10, 10, 10, 10);

Bu yourButton.imageView.contentMode = UIViewContentModeScaleAspectFit olmalıdır;
sdsykes

.İmageView ile denemedim. Oldukça iyi olmadan çalışıyor.
Tulleb

7

1 - Düğme varsayılan metnini temizle (önemli)

2 - görüntü gibi hizalamayı ayarlayın

3 - görüntü gibi içerik modunu ayarlayın

görüntü açıklamasını buraya girin


Güzel cevap dostum bana çok yardımcı oldu. Teşekkürler!
BharathRao

5

Benim için bunu yapan bir yöntemim var. Yöntem UIButton, görüntünün en boyunu alır ve uygun hale getirir.

-(void)makeImageAspectFitForButton:(UIButton*)button{
    button.imageView.contentMode=UIViewContentModeScaleAspectFit;
    button.contentHorizontalAlignment=UIControlContentHorizontalAlignmentFill;
    button.contentVerticalAlignment=UIControlContentVerticalAlignmentFill;
}

4

En temiz çözüm, Otomatik Yerleşimi kullanmaktır . Ben indirdi İçerik Sıkıştırma Direnci Öncelik Sesimin UIButtonve görüntü (belirtilmedi Arkaplan Resmi üzerinden) Interface Builder . Bundan sonra, düğmemin boyutunu tanımlayan birkaç kısıtlama ekledim (benim durumumda oldukça karmaşık) ve bir cazibe gibi çalıştı.


Bu benim için çalıştı - ancak yalnızca gerçek resmi değil, "Arka Plan Resmi" ni kullanmayı seçersem. Nasıl uygun görürsen! Bu beni KURUYEMİŞ tahrik ediyordu.
Andy

Xcode 6.2 altında bu benim için çalıştı ancak @AndrewHeinlein'in söylediği gibi kullanıldıBackground Image
RoLYroLL

3

Görüntüyü Görüntü özelliğine ayarladığınızdan, ancak Arka Plan olarak ayarlamadığınızdan emin olun


2

Arka plan resmi aslında en boy dolgusunu oldukça kolay bir şekilde ölçeklendirecek şekilde ayarlanabilir. UIButton'un bir alt sınıfında buna benzer bir şey yapmanız yeterlidir:

- (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;
}

Bu bir alt sınıf olmadan mümkün değil mi?
Iulian Onofrei

Bu cevap özellikle backgroundImage içindi. Ana görüntü için imageEdgeInsets ile maymun yapabilirsiniz.
Andy Poes

Biliyorum ve bunu bir alt sınıf olmadan başarmanın mümkün olup olmadığını istedim.
Iulian Onofrei

Bildiğim kadarıyla arka plan görüntüsünü alt sınıflandırma yapmadan ayarlayamazsınız.
Andy Poes

1

Swift 5.0

 myButton2.contentMode = .scaleAspectFit
 myButton2.contentHorizontalAlignment = .fill
 myButton2.contentVerticalAlignment = .fill

0

Xamarin.iOS (C #) için:

    myButton.VerticalAlignment = UIControlContentVerticalAlignment.Fill;
    myButton.HorizontalAlignment = UIControlContentHorizontalAlignment.Fill;
    myButton.ImageView.ContentMode = UIViewContentMode.ScaleAspectFit;

-1

Üç olay için UIButton görüntü görünümünün içerik modunu ayarlamanız yeterlidir. -

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

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

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

Düğme boyutunun KARE ve görüntü boyutunun dikdörtgen olup olmadığını vurgularken veya seçerken üç olay bcoz için kodumuz var, ardından vurgulama veya seçme sırasında kare görüntü gösterecektir.

Eminim senin için çalışacaktır.


Bir içerik modu ayarlamıyorsun, resmi ayarlıyorsun. Ve bunlar olay değil, eyaletler. Büyük bir karışıklık yaratıyorsun. Bu, soruyla tamamen alakasız.
manecosta
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.