2017-05-12 2 views
1

Ok, j'ai besoin de masquer un UICollectionView horizontal pour qu'il ressemble à un ruban. Mon homologue web dev l'a fait avec un SVG qu'il a utilisé comme couche de masquage.Masquer UIView (UICollectionView) correctement

Voici ma situation actuelle: enter image description here

Et voici ce que je dois (Photo de notre application Web): enter image description here

Petit détail dans l'image espacer côté, j'ai un SVG comme ceci: enter image description here

Ce que je peux convertir avec succès en code UIBezierPath (Paintcode):

let pathPath = UIBezierPath() 
pathPath.move(to: CGPoint(x: 0.05, y: 0)) 
pathPath.addCurve(to: CGPoint(x: 162.02, y: 3.8), controlPoint1: CGPoint(x: 0.05, y: 2.1), controlPoint2: CGPoint(x: 72.57, y: 3.8)) 
pathPath.addCurve(to: CGPoint(x: 324, y: 0), controlPoint1: CGPoint(x: 251.48, y: 3.8), controlPoint2: CGPoint(x: 324, y: 2.1)) 
pathPath.addLine(to: CGPoint(x: 324, y: 150.2)) 
pathPath.addCurve(to: CGPoint(x: 162.02, y: 154), controlPoint1: CGPoint(x: 324, y: 152.3), controlPoint2: CGPoint(x: 251.48, y: 154)) 
pathPath.addCurve(to: CGPoint(x: 0.05, y: 150.2), controlPoint1: CGPoint(x: 72.57, y: 154), controlPoint2: CGPoint(x: 0.05, y: 152.3)) 
pathPath.addCurve(to: CGPoint(x: 0, y: 0.17), controlPoint1: CGPoint(x: 0.05, y: 148.1), controlPoint2: CGPoint(x: 0, y: 0.17)) 
pathPath.usesEvenOddFillRule = true 
UIColor.lightGray.setFill() 
pathPath.fill() 

Maintenant, qu'est-ce que je fais?

Répondre

1

Vous devez utiliser la propriété mask de votre UICollectionView en la définissant sur une vue dont la couche alpha indique la partie de l'UICollectionView que vous souhaitez masquer. Dans les grandes lignes ce sera probablement quelque chose comme:

// If you don't have a custom subclass of UICollectionView... you can handle the resize in the 
// UICollectionViewController or whatever view contoller is handling your view. 
// 
// If you do have a custom subclass of UICollectionView... you could do something similar 
// in layoutSubviews. 

class MyViewController : UICollectionViewController { 

    // recreate the mask after the view lays out it's subviews 
    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 

     if let maskImage = createMaskingImage(size: self.view.bounds.size) { 
      let maskView = UIView(frame: self.view.bounds) 
      maskView.layer.contents = maskImage 

      self.view.mask = maskView 
     } 
    } 
} 

// create a masking image for a view of the given size 
func createMaskingImage(size: CGSize) -> UIImage? { 

    let drawingBounds = CGRect(origin: CGPoint.zero, size: size) 

    UIGraphicsBeginImageContext(size) 

    // We're going to jump down to the level of cgContext for scaling 
    // You might be able to do this from the level of UIGraphics, but I don't know how so... 
    // Implicitly unwrapped optional, but if we can't get a CGContext we're in trouble 

    let cgContext = UIGraphicsGetCurrentContext()! 
    let maskingPath = createMaskingPath() 
    let pathBounds = maskingPath.bounds; 

    cgContext.saveGState() 

    // Clearing the image may not strictly be necessary 
    cgContext.clear(drawingBounds) 

    // Scale the context so that when we draw the path it fits in the drawing bounds 
    // Could just use "size" here instead of drawingBounds.size, but I think this makes it a 
    // little more explicit that we're matching up two rects 
    cgContext.scaleBy(x: drawingBounds.size.width/pathBounds.size.width, 
         y: drawingBounds.size.height/pathBounds.size.height) 
    cgContext.setFillColor(UIColor.lightGray.cgColor) 
    cgContext.addPath(maskingPath.cgPath) 
    cgContext.fillPath(using: .evenOdd) 

    cgContext.restoreGState() 

    let image = UIGraphicsGetImageFromCurrentImageContext() 
    UIGraphicsEndImageContext() 

    return image 
} 

func createMaskingPath() -> UIBezierPath { 
    let path = UIBezierPath() 

    path.move(to: CGPoint(x: 0.05, y: 0)) 
    path.addCurve(to: CGPoint(x: 162.02, y: 3.8), controlPoint1: CGPoint(x: 0.05, y: 2.1), controlPoint2: CGPoint(x: 72.57, y: 3.8)) 
    path.addCurve(to: CGPoint(x: 324, y: 0), controlPoint1: CGPoint(x: 251.48, y: 3.8), controlPoint2: CGPoint(x: 324, y: 2.1)) 
    path.addLine(to: CGPoint(x: 324, y: 150.2)) 
    path.addCurve(to: CGPoint(x: 162.02, y: 154), controlPoint1: CGPoint(x: 324, y: 152.3), controlPoint2: CGPoint(x: 251.48, y: 154)) 
    path.addCurve(to: CGPoint(x: 0.05, y: 150.2), controlPoint1: CGPoint(x: 72.57, y: 154), controlPoint2: CGPoint(x: 0.05, y: 152.3)) 
    path.addCurve(to: CGPoint(x: 0, y: 0.17), controlPoint1: CGPoint(x: 0.05, y: 148.1), controlPoint2: CGPoint(x: 0, y: 0.17)) 

    return path 
} 
+0

Merci Scott. Vous avez été partout sur mes questions, lol. Comment voulez-vous écrire ce code pour une taille changeante? Le contenu que j'ai projeté est un 'UITableViewCell'. Ainsi, le 'UICollectionView' incorporé change des cadres. Remplacer 'layoutIfNeeded()' quelque part et dessiner là? –

+0

OK. J'ai édité la réponse pour tenir compte de la mise à l'échelle. Notez que je redimensionne le CGPath, ce qui signifie que plus vous agrandirez ou plus la «profondeur» du ruban changera. Vous pouvez résoudre ce problème en modifiant procéduralement la forme de masquage du ruban. –

+0

Je devrais aussi mentionner que pendant que j'ai compilé ce code dans un Playground, je ne l'ai pas complètement exécuté –