2017-07-26 2 views
14

Ce que j'essaie essentiellement de faire, c'est d'avoir une étiquette de texte «découper» un trou en forme de texte dans la vue. J'ai essayé d'utiliser self.mask = uiLabel, mais ceux qui ont refusé de positionner le texte correctement, alors je suis en train d'approcher cela via Core Graphics.Core Graphics CGImage Masque n'affectant pas

est ici le code qui ne fonctionne pas (dans le draw(_ rect: CGRect)):

let context = (UIGraphicsGetCurrentContext())! 

    // Set mask background color 
    context.setFillColor(UIColor.black.cgColor) 
    context.fill(rect) 

    context.saveGState() 


    let paragraphStyle = NSMutableParagraphStyle() 
    paragraphStyle.alignment = .center 

    let attributes = [ 
     NSParagraphStyleAttributeName: paragraphStyle, 
     NSFontAttributeName: UIFont.systemFont(ofSize: 16, weight: UIFontWeightMedium), 
     NSForegroundColorAttributeName: UIColor.white 
    ] 

    let string = NSString(string: "LOGIN") 

    // This wouldn't vertically align so we calculate the string size and create a new rect in which it is vertically aligned 
    let size = string.size(attributes: attributes) 
    let position = CGRect(
     x: rect.origin.x, 
     y: rect.origin.y + (rect.size.height - size.height)/2, 
     width: rect.size.width, 
     height: size.height 
    ) 

    context.translateBy(x: 0, y: rect.size.height) 
    context.scaleBy(x: 1, y: -1) 
    string.draw(
     in: position, 
     withAttributes: attributes 
    ) 

    let mask = (context.makeImage())! 

    context.restoreGState() 

    // Redraw with created mask 
    context.clear(rect) 

    context.saveGState() 
    // !!!! Below line is the problem 
    context.clip(to: rect, mask: mask) 
    context.restoreGState() 

Essentiellement, j'ai créé avec succès le code pour créer une CGImage (la variable mask) qui est le masque que je veux appliquer à l'image entière.

La ligne marquée lorsque a remplacé avec context.draw(mask, in: rect) (pour afficher le masque) s'affiche correctement. Le masque montre (correctement) que:

enter image description here:

Cependant, une fois que j'essaie d'appliquer ce masque (en utilisant le context.clip(to: rect, mask: mask)) rien ne se passe !. Résultat réel:

Nothing changing

Résultat souhaité est:

Desired result

mais pour une raison quelconque le masque n'est pas correctement appliqué.


Ce code semble fonctionner correctement car j'ai lu et relu les documents. J'ai également essayé de créer le masque dans un CGContext séparé qui ne fonctionnait pas. Aussi quand j'ai essayé de convertir le CGImage (mask) en CGColorSpaceCreateDeviceGray() en utilisant .copy(colorSpace:), il a retourné nil. Cela fait deux jours que je suis là pour toute aide.

+0

J'ai eu un problème similaire une fois , mais ma configuration est légèrement différente: Un 'UIControl' c sous-classe ustom avec une sous-vue 'UILabel'. –

+0

Dans mon cas, appeler 'setNeedsDisplay()' sur la sous-vue label avant de rendre le mas le corrige. –

Répondre

1

Si vous voulez que l'étiquette ait un texte entièrement translucide, vous pouvez utiliser des modes de fusion au lieu de masques.

public class KnockoutLabel: UILabel { 
    public override func draw(_ rect: CGRect) { 
     let context = UIGraphicsGetCurrentContext()! 
     context.setBlendMode(.clear) 

     self.drawText(in: rect) 
    } 
} 

Assurez-vous de mettre isOpaque-false bien; par défaut, la vue suppose qu'elle est opaque, car vous utilisez une couleur d'arrière-plan opaque.

+0

Je ne sais pas de quoi il s'agit, mais cela ne semble pas bien fonctionner avec 'UIVisualEffectView'. Les autres modes de fusion ne le sont pas non plus – Downgoat

+0

@Downgoat Qu'essayez-vous exactement d'accomplir et quel est le problème? –

+0

même problème que la question, le bouton semble être inchangé lors du réglage du mode de fusion. Ceci est censé être juste un effet d'interface utilisateur – Downgoat

1

Je ne suis pas sûr que vous apprécierez le code ci-dessous. Il a été fait en utilisant le PaintCode. Le texte sera toujours au centre du rectangle arrondi. J'espère que cela vous aidera.

code

, le mettre à l'intérieur de tirage (_ rect: CGRect):

//// General Declarations 
    let context = UIGraphicsGetCurrentContext() 

    //// Color Declarations - just to make a gradient same as your button have 
    let gradientColor = UIColor(red: 0.220, green: 0.220, blue: 0.223, alpha: 1.000) 
    let gradientColor2 = UIColor(red: 0.718, green: 0.666, blue: 0.681, alpha: 1.000) 
    let gradientColor3 = UIColor(red: 0.401, green: 0.365, blue: 0.365, alpha: 1.000) 

    //// Gradient Declarations 
    let gradient = CGGradient(colorsSpace: nil, colors: [gradientColor.cgColor, gradientColor3.cgColor, gradientColor2.cgColor] as CFArray, locations: [0, 0.55, 1])! 


    //// Subframes 
    let group: CGRect = CGRect(x: rect.minX, y: rect.minY, width: rect.width, height: rect.height) 


    //// Group 
    context.saveGState() 
    context.beginTransparencyLayer(auxiliaryInfo: nil) 


    //// Rectangle Drawing 
    let rectanglePath = UIBezierPath(roundedRect: group, cornerRadius: 5) 
    context.saveGState() 
    rectanglePath.addClip() 
    let rectangleRotatedPath = UIBezierPath() 
    rectangleRotatedPath.append(rectanglePath) 
    var rectangleTransform = CGAffineTransform(rotationAngle: -99 * -CGFloat.pi/180) 
    rectangleRotatedPath.apply(rectangleTransform) 
    let rectangleBounds = rectangleRotatedPath.cgPath.boundingBoxOfPath 
    rectangleTransform = rectangleTransform.inverted() 
    context.drawLinearGradient(gradient, 
           start: CGPoint(x: rectangleBounds.minX, y: rectangleBounds.midY).applying(rectangleTransform), 
           end: CGPoint(x: rectangleBounds.maxX, y: rectangleBounds.midY).applying(rectangleTransform), 
           options: []) 
    context.restoreGState() 


    //// Text Drawing 
    context.saveGState() 
    context.setBlendMode(.destinationOut) 

    let textRect = group 
    let textTextContent = "LOGIN" 
    let textStyle = NSMutableParagraphStyle() 
    textStyle.alignment = .center 
    let textFontAttributes = [ 
     NSFontAttributeName: UIFont.systemFont(ofSize: 16, weight: UIFontWeightBold), 
     NSForegroundColorAttributeName: UIColor.black, 
     NSParagraphStyleAttributeName: textStyle, 
     ] 

    let textTextHeight: CGFloat = textTextContent.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height 
    context.saveGState() 
    context.clip(to: textRect) 
    textTextContent.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight)/2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes) 
    context.restoreGState() 

    context.restoreGState() 


    context.endTransparencyLayer() 
    context.restoreGState() 

Résultats:

enter image description here

enter image description here

enter image description here