1. 현재 뷰의 전체 스크린샷 추출
extension UIView {
/// 현재 뷰의 전체 스크린샷 추출
func screenCapture() -> UIImage {
let snapview = UIScreen.main.snapshotView(afterScreenUpdates: true)
let renderer = UIGraphicsImageRenderer(size: snapview.bounds.size)
let image = renderer.image { _ in
self.addSubview(snapview)
self.drawHierarchy(in: snapview.bounds, afterScreenUpdates: true)
snapview.removeFromSuperview()
}
return image
}
}
2. 일반적인 기능들
extension UIView {
static let kLayerNameEdgeBorder = "EdgeBorderLayer"
static let kLayerNameShadowPath = "ShadowPathLayer"
static let kLayerNameGradientBorder = "GradientBorderLayer"
static let kLayerNameGradientBackground = "GradientBackgroundLayer"
///현재 뷰의 parent ViewController 찾기
var parentViewController: UIViewController? {
var parentResponder: UIResponder? = self
while parentResponder != nil {
parentResponder = parentResponder!.next
if let viewController = parentResponder as? UIViewController {
return viewController
}
}
return nil
}
/// 테그번호로 뷰 가져오기
func getView(viewTag: Int) -> Any {
return self.viewWithTag(viewTag) as Any
}
/// 현재 뷰에 Blur 효과 적용
func addBlurToView(style: UIBlurEffect.Style, alpha: CGFloat){
let blurEffect:UIBlurEffect = UIBlurEffect(style: style)
let blurredEffectView = UIVisualEffectView(effect: blurEffect)
blurredEffectView.frame = self.bounds
blurredEffectView.alpha = alpha
blurredEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
self.addSubview(blurredEffectView)
self.sendSubviewToBack(blurredEffectView)
}
/// 적용된 Blur 효과 제거
func removeBlurFromView(){
for subView in self.subviews{
if let subView = subView as? UIVisualEffectView{
subView.removeFromSuperview()
}
}
}
/// 뷰의 모서리 둥근 모양 및 그림자 효과
func setCornerRadiusWithShadow(cornerRadius: CGFloat, masksToBounds :Bool = false) {
if layer.shadowPath != nil {
return
}
layer.shadowColor = UIColor.darkGray.cgColor
layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
layer.shadowRadius = cornerRadius
layer.shadowOpacity = 0.3//1.0
layer.masksToBounds = masksToBounds
layer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: 8).cgPath
layer.cornerRadius = cornerRadius
}
/// 전체 둥근 모양 설정
func harfCornerRadius() {
self.layer.cornerRadius = self.frame.height/2
}
/// 부분적 둥근 모서리 설정 (self.view.edgeCornerRadius(corners: [.topLeft, .topRight], radius: 10.0))
func edgeCornerRadius(corners: UIRectCorner, radius: CGFloat, clipsToBounds: Bool = true, width: CGFloat = 0.0, borderColor: UIColor = .white) {
// Corners Radius
let mask = CAShapeLayer()
mask.frame = bounds
mask.path = UIBezierPath(roundedRect: bounds,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius)).cgPath
// 레이어 경계선 위로 하위뷰가 벗어나있을 경우 잘림. (10 이하 버전용)
//layer.mask = mask
//clipsToBounds = false
/* 11 이상 버전 사용
- clipsToBounds true일 경우 SubView가 외곽으로 벗어나는 UI의 경우 짤리기 때문에 false로 설정
- 그 외 일반적인 상황에서는 default true 값을 사용해야 CornerRaidus적용됨.
*/
self.clipsToBounds = clipsToBounds
layer.cornerRadius = radius
layer.maskedCorners = CACornerMask(rawValue: corners.rawValue)
// Add Border
if width > 0 {
removeLayer(layername: UIView.kLayerNameEdgeBorder)
let borderLayer = CAShapeLayer()
borderLayer.path = mask.path // Reuse the Bezier path
borderLayer.fillColor = UIColor.clear.cgColor
borderLayer.strokeColor = borderColor.cgColor
borderLayer.lineWidth = width
borderLayer.frame = bounds
borderLayer.name = UIView.kLayerNameEdgeBorder
layer.addSublayer(borderLayer)
}
}
/// 뷰의 테두리 컬러 적용
func borderColor(width: CGFloat, borderColor color: UIColor) {
self.layer.borderWidth = width
self.layer.borderColor = color.cgColor
}
/// 뷰의 백그라운드 그라디언트 컬러 적용
func addBackgroundGradient(colors: [UIColor],
cornerRadius: CGFloat = 5.0,
opacity: CGFloat = 1.0,
shadow: Bool = false,
startPoint: CGPoint = CGPoint(x: 0.0, y: 0.0),
endPoint: CGPoint = CGPoint(x: 1, y: 0)) {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = colors.map { return $0.cgColor }
gradientLayer.startPoint = startPoint
gradientLayer.endPoint = endPoint
// gradientLayer.locations = [0.0, 1.0]
gradientLayer.opacity = Float(opacity)
gradientLayer.frame = self.bounds
// if cornerRadius == true {
gradientLayer.cornerRadius = cornerRadius //self.frame.height/2
// }
if shadow {
gradientLayer.shadowColor = UIColor.darkGray.cgColor
gradientLayer.shadowOffset = CGSize(width: 2.5, height: 2.5)
gradientLayer.shadowRadius = 5.0
gradientLayer.shadowOpacity = 0.3
}
gradientLayer.name = UIView.kLayerNameGradientBackground
gradientLayer.masksToBounds = false
self.layer.insertSublayer(gradientLayer, at: 0)
}
/// 뷰의 테두리에 그라디언트 컬러 효과 적용
public func addBorderGradient(
width: CGFloat,
colors: [UIColor],
cornerRadius: CGFloat = 5.0,
startPoint: CGPoint = CGPoint(x: 0.0, y: 0.0),
endPoint: CGPoint = CGPoint(x: 1, y: 0)) {
// removeLayer(layername: UIView.kLayerNameGradientBorder)
let existedBorder = gradientBorderLayer()
let border = existedBorder ?? CAGradientLayer()
border.frame = self.bounds
border.colors = colors.map { return $0.cgColor }
// border.opacity = 1.0
border.startPoint = startPoint
border.endPoint = endPoint
border.name = UIView.kLayerNameGradientBorder
border.cornerRadius = cornerRadius
let mask = CAShapeLayer()
// mask.path = UIBezierPath(roundedRect: bounds, cornerRadius: 8).cgPath
mask.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath //0).cgPath
mask.fillColor = UIColor.clear.cgColor
mask.strokeColor = UIColor.white.cgColor
mask.lineWidth = width
border.mask = mask
let exists = existedBorder != nil
if !exists {
layer.addSublayer(border)
// layer.layoutIfNeeded()
// self.layer.insertSublayer(border, at: 0)
} else {
layer.layoutIfNeeded()
}
}
/*
상단 뷰 등근 곡선
*/
func addTopRoundedEdge(desiredCurve:CGFloat?)
{
let offset:CGFloat = self.frame.width/desiredCurve!
let bounds: CGRect = self.bounds
let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y+bounds.size.height / 2, width: bounds.size.width, height: bounds.size.height / 2)
let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)
let ovalBounds: CGRect = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)
// Create the shape layer and set its path
let maskLayer: CAShapeLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = rectPath.cgPath
// Set the newly created shape layer as the mask for the view's layer
self.layer.mask = maskLayer
}
/* 하단 뷰 움푹파인 등근 곡선
* bgView.addBottomRoundedEdge(desiredCurve: 1.5)
*/
func addBottomRoundedEdge(desiredCurve: CGFloat?) {
let offset: CGFloat = self.frame.width / desiredCurve!
let bounds: CGRect = self.bounds
let rectBounds: CGRect = CGRect(x: bounds.origin.x, y: bounds.origin.y, width: bounds.size.width, height: bounds.size.height / 2)
let rectPath: UIBezierPath = UIBezierPath(rect: rectBounds)
let ovalBounds: CGRect = CGRect(x: bounds.origin.x - offset / 2, y: bounds.origin.y, width: bounds.size.width + offset, height: bounds.size.height)
let ovalPath: UIBezierPath = UIBezierPath(ovalIn: ovalBounds)
rectPath.append(ovalPath)
// Create the shape layer and set its path
let maskLayer: CAShapeLayer = CAShapeLayer()
maskLayer.frame = bounds
maskLayer.path = rectPath.cgPath
// Set the newly created shape layer as the mask for the view's layer
self.layer.mask = maskLayer
}
private func gradientBorderLayer() -> CAGradientLayer? {
let borderLayers = layer.sublayers?.filter {
return $0.name == UIView.kLayerNameGradientBorder }
if borderLayers?.count ?? 0 > 1 {
fatalError()
}
return borderLayers?.first as? CAGradientLayer
}
func removeLayer(layername: String) {
if let sublayers = self.layer.sublayers {
for layer: CALayer in sublayers {
if (layer.name == layername) {
// log(direction: .UI, ofType: self, datas: "=> UIView removeLayer \(String(describing: layername))")
layer.removeFromSuperlayer()
break
}
}
}
/*
guard let sublayers = self.layer.sublayers else {
return
}
if sublayers.count > 0 {
sublayers.forEach {
if $0.name == layername {
$0.removeFromSuperlayer()
}
}
}*/
}
public func removeGradientBorder() {
self.gradientBorderLayer()?.removeFromSuperlayer()
}
}
3. TapGestureRecognizer (탭 제스쳐)
** WkWebView 에서는 동작 안함. (WKWebView는 별도로 탭 제스쳐 처리해줘야됨)
// MARK: TagGesture
extension UIView {
// In order to create computed properties for extensions, we need a key to
// store and access the stored property
fileprivate struct AssociatedObjectKeys {
static var tapGestureRecognizer = "MediaViewerAssociatedObjectKey_mediaViewer"
}
fileprivate typealias Action = (() -> Void)?
// Set our computed property type to a closure
fileprivate var tapGestureRecognizerAction: Action? {
set {
if let newValue = newValue {
// Computed properties get stored as associated objects
objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
get {
let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action
return tapGestureRecognizerActionInstance
}
}
// This is the meat of the sauce, here we create the tap gesture recognizer and
// store the closure the user passed to us in the associated object we declared above
public func addTapGestureRecognizer(action: (() -> Void)?) {
self.isUserInteractionEnabled = true
self.tapGestureRecognizerAction = action
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
self.isUserInteractionEnabled = true
self.addGestureRecognizer(tapGestureRecognizer)
}
// Every time the user taps on the UIImageView, this function gets called,
// which triggers the closure we stored
@objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
if let action = self.tapGestureRecognizerAction {
action?()
} else {
print("no action")
}
}
}
'Swift > Extention' 카테고리의 다른 글
[SWIFT]String Extension 유용한 기능 (0) | 2023.04.24 |
---|---|
[SWIFT]enum Extension CaseIterable 사용 (0) | 2023.04.24 |
[SWIFT]URL Extention 유용한 정보 (0) | 2023.04.24 |
[SWIFT]UIDevice Extention 유용한 기능 (0) | 2023.04.18 |
[SWIFT]로그 예쁘게 찍기 (0) | 2021.11.16 |