2015-03-23 15 views
7

Na podstawie poniższej source code:Jak utworzyć w Swift zdjęcie z okrągłym profilem lub zaokrąglonym narożnikiem z krawędzią, która nie przecieka?

@IBOutlet var myUIImageView: UIImageView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.makingRoundedImageProfileWithRoundedBorder() 
    } 

    private func makingRoundedImageProfileWithRoundedBorder() {  
     // Making a circular image profile. 
//  self.myUIImageView.layer.cornerRadius = self.myUIImageView.frame.size.width/2 
     // Making a rounded image profile. 
     self.myUIImageView.layer.cornerRadius = 20.0 

     self.myUIImageView.clipsToBounds = true 

     // Adding a border to the image profile 
     self.myUIImageView.layer.borderWidth = 10.0 
     self.myUIImageView.layer.borderColor = UIColor.whiteColor().CGColor 
    } 

Rzeczywiście jestem w stanie renderować okrągły lub zaokrąglony UIImageView, ale problemem jest to, że jeśli dodamy granicę, obraz trochę przecieka. Gorzej z okrągłym UIImageView, przecieka, gdy granica jest zgięta, więc WYSYŁA WSZĘDZIE! Można znaleźć zrzut ekranu poniżej wynik:

UIImageView rendered

żaden sposób naprawić w Swift? Każdy przykładowy kod, który odpowie na to pytanie, zostanie wysoko oceniony.

Uwaga: w miarę możliwości rozwiązanie musi być zgodne z systemem iOS 7 i 8+.

Odpowiedz

5

pierwsze rozwiązanie

oparciu o sugestię @Jesper Schlager

„Jeśli mogę zasugerować szybki i brudny roztwór:

zamiast dodawać obramowanie do widoku obrazu, można dodać kolejny biały widok poniżej widoku obrazu, aby widok rozciągnął się o 10 punktów w dowolnym kierunku i nadał mu promień naroża o wartości 20,0. Daj obrazowi widok o promieniu naroża 10,0."

Proszę znaleźć Swift realizację poniżej:

import UIKit 

class ViewController: UIViewController { 

    @IBOutlet var myUIImageView: UIImageView! 

    @IBOutlet var myUIViewBackground: UIView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Making a circular UIView: cornerRadius = self.myUIImageView.frame.size.width/2 
     // Making a rounded UIView: cornerRadius = 10.0 
     self.roundingUIView(self.myUIImageView, cornerRadiusParam: 10) 
     self.roundingUIView(self.myUIViewBackground, cornerRadiusParam: 20) 
    } 

    private func roundingUIView(let aView: UIView!, let cornerRadiusParam: CGFloat!) { 
     aView.clipsToBounds = true 
     aView.layer.cornerRadius = cornerRadiusParam 
    } 

} 

II Rozwiązanie

byłoby ustawić maskę okrąg nad CALayer

Proszę znaleźć . Cel-C wdrożenie tego drugiego rozwiązania poniżej:

CALayer *maskedLayer = [CALayer layer]; 
[maskedLayer setFrame:CGRectMake(50, 50, 100, 100)]; 
[maskedLayer setBackgroundColor:[UIColor blackColor].CGColor]; 

UIBezierPath *maskingPath = [UIBezierPath bezierPath]; 
[maskingPath addArcWithCenter:maskedLayer.position 
         radius:40 
        startAngle:0 
        endAngle:360 
        clockwise:TRUE]; 

CAShapeLayer *maskingLayer = [CAShapeLayer layer]; 
[maskingLayer setPath:maskingPath.CGPath]; 

[maskedLayer setMask:maskingLayer]; 
[self.view.layer addSublayer:maskedLayer]; 

Jeśli wykomentuj z linii UIBezierPath *maskingPath = [UIBezierPath bezierPath]; przez [maskedLayer setMask:maskingLayer]; widać, że warstwa jest kwadratem. Jednak gdy te linie nie są komentowane, warstwa jest kołem.

Uwaga: Nie testowałem tego drugiego rozwiązania ani nie wprowadziłem implementacji Swift, więc możesz go przetestować i dać mi znać, czy działa, czy nie, za pośrednictwem sekcji komentarzy poniżej. Możesz również edytować ten wpis, dodając implementację Swift tego drugiego rozwiązania.

+0

Uwaga: Ścieżka maskująca jest funkcjonalna, ale ma chrupiące, aliasingowane krawędzie, których nie udało mi się poprawić na http://stackoverflow.com/questions/37092333/path-based-mask-with-nice-iumi-aliasing – SimplGy

0

Pracowałem nad ulepszeniem kodu, ale ciągle się zawiesza. Będę nad tym pracował, ale wydaje mi się, że mam działającą wersję:

Edycja Zaktualizowana nieco ładniejszą wersją. Nie podoba mi się sposób init:coder ale być może, że może zbitek/ulepszona

class RoundedImageView: UIView { 
    var image: UIImage? { 
     didSet { 
      if let image = image { 
       self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale) 
      } 
     } 
    } 
    var cornerRadius: CGFloat? 

    private class func frameForImage(image: UIImage) -> CGRect { 
     return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale) 
    } 

    override func drawRect(rect: CGRect) { 
     if let image = self.image { 
      image.drawInRect(rect) 

      let cornerRadius = self.cornerRadius ?? rect.size.width/10 
      let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius) 
      UIColor.whiteColor().setStroke() 
      path.lineWidth = cornerRadius 
      path.stroke() 
     } 
    } 
} 

let image = UIImage(named: "big-teddy-bear.jpg") 

let imageView = RoundedImageView() 
imageView.image = image 

Daj mi znać, jeśli to jest coś takiego, czego szukasz.

Trochę wyjaśnienie:

jak jestem pewien, że znaleziony, „granica”, które mogą ubiegać iOS nie jest doskonały, i pokazuje rogi z jakiegoś powodu. Znalazłem kilka innych rozwiązań, ale żaden z nich nie działał. Powodem tego jest podklasa UIView, a nie UIImageView, jest to drawRect: is not called for subclasses of UIImageView. Nie jestem pewien co do wykonania tego kodu, ale wydaje się dobrze z moim (ograniczona) testowanie

Kod oryginalny:

class RoundedImageView: UIView { 

    var image: UIImage? { 
     didSet { 
      if let image = image { 
       self.frame = CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale) 
      } 
     } 
    } 

    private class func frameForImage(image: UIImage) -> CGRect { 
     return CGRect(x: 0, y: 0, width: image.size.width/image.scale, height: image.size.width/image.scale) 
    } 

    override func drawRect(rect: CGRect) { 
     if let image = self.image { 
      self.image?.drawInRect(rect) 

      let path = UIBezierPath(roundedRect: rect, cornerRadius: 50) 
      UIColor.whiteColor().setStroke() 
      path.lineWidth = 10 
      path.stroke() 
     } 
    } 
} 

let image = UIImage(named: "big-teddy-bear.jpg") 

let imageView = RoundedImageView() 
imageView.image = image 
imageView.layer.cornerRadius = 50 
imageView.clipsToBounds = true 
+0

Awaria kodu + Chciałbym nadal używać UIImageView w moim scenorysie i nie używać UIView jeśli to możliwe. Niestety nie pasuje to do moich potrzeb. –

+0

Nie jestem pewien, czy jest to możliwe z 'UIImageView', ale chciałbym zobaczyć rozwiązanie, jeśli je masz. Czy możesz zamieścić więcej informacji o awarii? Być może będziesz w stanie użyć 'IBDesignable', aby działał w narzędziu do budowania interfejsu, ale nie jestem pewien. Czy zgodziłeś się z jakiegoś powodu? –

+0

self.image.drawInRect (rect) // błąd krytyczny: nieoczekiwanie znaleziono zero podczas rozpakowywania wartości opcjonalnej –

0

Jeśli mogę zasugerować szybki i brudny roztwór:

Zamiast dodając obramowanie do widoku obrazu, możesz dodać kolejny biały widok pod widokiem obrazu. Spraw, by widok rozciągnął się o 10 punktów w dowolnym kierunku i nadał mu promień naroża równy 20,0. Daj obrazowi widok o promieniu naroża 10,0.

+0

Dziękuję Jesperowi Schlägerowi, rozwiązaniu, które rozwiązuje problem i wymaga mniej kodu niż ręczne dodanie granicy do UIView. Jednak teoretycznie moglibyśmy rozwiązać ten problem, dodając UIImage do UIView i ręcznie rysując granicę wokół UIImage, myślę, że to właśnie @ Duose Duffy próbuje wdrożyć w swojej odpowiedzi poniżej. –

Powiązane problemy