From 65d63e36635587097cab2dc6cf9adb22ff6b9377 Mon Sep 17 00:00:00 2001 From: Filip Wiesner Date: Mon, 30 Oct 2017 00:39:10 +0100 Subject: [PATCH] Added title gravity - appearence property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added title gravity property into SMSegment. It enables user to set position of title relatively to image. Possible positions: -> right - default position -> bottom - title is below image -> top - title is on top of image -> left - title is on left of image Following improvements and fixes caused by rework: - Fix: wrong title height in horizontal layouts - Fix: Shrink image if content doesnť fit If height of label (with applied font) and image is bigger then control height, shrink image to fit label. -> Helps on vertical organise mode --- .../SMSegmentView/SMSegment.swift | 84 +++++++++++++++++-- .../SMSegmentView/SMSegmentAppearance.swift | 11 ++- .../SMSegmentViewConstants.swift | 7 ++ 3 files changed, 96 insertions(+), 6 deletions(-) diff --git a/SMSegmentViewController/SMSegmentView/SMSegment.swift b/SMSegmentViewController/SMSegmentView/SMSegment.swift index f6accbc..20a441b 100644 --- a/SMSegmentViewController/SMSegmentView/SMSegment.swift +++ b/SMSegmentViewController/SMSegmentView/SMSegment.swift @@ -85,25 +85,99 @@ open class SMSegment: UIView { verticalMargin = appearance.contentVerticalMargin } - var imageViewFrame = CGRect(x: 0.0, y: verticalMargin, width: 0.0, height: self.frame.size.height - verticalMargin*2) + var imageViewFrame = CGRect(x: 0.0, y: verticalMargin, width: 0.0, height: self.frame.size.height - verticalMargin * 2) if self.onSelectionImage != nil || self.offSelectionImage != nil { // Set imageView as a square - imageViewFrame.size.width = self.frame.size.height - verticalMargin*2 + imageViewFrame.size.width = imageViewFrame.height distanceBetween = 5.0 } + // Initialize empty title frame + var titleViewFrame: CGRect = CGRect() + // If there's no text, align image in the centre - // Otherwise align text & image in the centre + // Otherwise align text & image in the centre and apply title gravity self.label.sizeToFit() if self.label.frame.size.width == 0.0 { imageViewFrame.origin.x = max((self.frame.size.width - imageViewFrame.size.width) / 2.0, 0.0) } else { - imageViewFrame.origin.x = max((self.frame.size.width - imageViewFrame.size.width - self.label.frame.size.width) / 2.0 - distanceBetween, 0.0) + titleViewFrame.size.width = self.label.frame.size.width + + switch self.appearance?.titleGravity { + case .some(SMSTitleGravity.bottom): + // Setup title width and height properties according to image size + titleViewFrame.size.height = self.label.frame.size.height // Need to be as small as possible to fit + + // Place image horizontally in centre and vertically to the top + vertical margin (changed to fit two vertical items) + imageViewFrame.size.height = self.frame.size.height - verticalMargin * 2.5 + + if imageViewFrame.size.height + self.label.font.lineHeight > self.frame.size.height { + imageViewFrame.size.height -= self.label.font.lineHeight / 2 + } + + imageViewFrame.size.width = imageViewFrame.size.height + imageViewFrame.origin.x = (self.frame.size.width - imageViewFrame.size.width)/2 + imageViewFrame.origin.y = verticalMargin / 2 + + // Place the title horizontally in centre and vertivally below image + vertical margin (changed to fit two vertical items) + titleViewFrame.origin.x = (self.frame.size.width - titleViewFrame.size.width)/2 + titleViewFrame.origin.y = imageViewFrame.size.height + verticalMargin / 1.5 + break + case .some(SMSTitleGravity.top): + // Setup title width and height properties according to image size + titleViewFrame.size.height = self.label.frame.size.height // Need to be as small as possible to fit + + // Place title horizontally in centre and vertically to the top + vertical margin (changed to fit two vertical items) + titleViewFrame.origin.x = (self.frame.size.width - titleViewFrame.size.width)/2 + titleViewFrame.origin.y = verticalMargin / 2 + + // Place the image horizontally in centre and vertivally below title + vertical margin (changed to fit two vertical items) + imageViewFrame.size.height = self.frame.size.height - verticalMargin * 2.5 + + if imageViewFrame.size.height + self.label.font.lineHeight > self.frame.size.height { + imageViewFrame.size.height -= self.label.font.lineHeight / 2 + } + + imageViewFrame.size.width = imageViewFrame.size.height + imageViewFrame.origin.x = (self.frame.size.width - imageViewFrame.size.width)/2 + imageViewFrame.origin.y = titleViewFrame.size.height + verticalMargin / 1.5 + break + case .some(SMSTitleGravity.left): + // Setup title width and height properties according to image size + titleViewFrame.size.height = self.frame.size.height - verticalMargin * 2 + + // If left space > 0, set half of it as initial X point of title + titleViewFrame.origin + .x = max( + (self.frame.size.width - imageViewFrame.size.width - self.label.frame.size.width) / 2.0 - distanceBetween, + 0.0 + ) + + titleViewFrame.origin + .y = verticalMargin + + // Place image to the right of title + imageViewFrame.origin.x = titleViewFrame.origin.x + titleViewFrame.size.width + distanceBetween + break + + default: + // Setup title width and height properties according to image size + titleViewFrame.size.width = self.label.frame.size.width + titleViewFrame.size.height = self.frame.size.height - verticalMargin * 2 + // If left space > 0, set half of it as initial X point og image + imageViewFrame.origin.x = max( + (self.frame.size.width - imageViewFrame.size.width - self.label.frame.size.width) / 2.0 - distanceBetween, + 0.0 + ) + // Place title to the right of image + titleViewFrame.origin.x = imageViewFrame.origin.x + imageViewFrame.size.width + distanceBetween + titleViewFrame.origin.y = verticalMargin + } } self.imageView.frame = imageViewFrame - self.label.frame = CGRect(x: imageViewFrame.origin.x + imageViewFrame.size.width + distanceBetween, y: verticalMargin, width: self.label.frame.size.width, height: self.frame.size.height - verticalMargin * 2) + self.label.frame = titleViewFrame } // MARK: Selections diff --git a/SMSegmentViewController/SMSegmentView/SMSegmentAppearance.swift b/SMSegmentViewController/SMSegmentView/SMSegmentAppearance.swift index 67672eb..8fff46c 100644 --- a/SMSegmentViewController/SMSegmentView/SMSegmentAppearance.swift +++ b/SMSegmentViewController/SMSegmentView/SMSegmentAppearance.swift @@ -37,6 +37,8 @@ open class SMSegmentAppearance { open var titleOnSelectionFont: UIFont open var titleOffSelectionFont: UIFont + open var titleGravity: SMSTitleGravity + open var contentVerticalMargin: CGFloat @@ -50,11 +52,12 @@ open class SMSegmentAppearance { self.titleOffSelectionColour = UIColor.darkGray self.titleOnSelectionFont = UIFont.systemFont(ofSize: 17.0) self.titleOffSelectionFont = UIFont.systemFont(ofSize: 17.0) + self.titleGravity = SMSTitleGravity.right self.contentVerticalMargin = 5.0 } - public init(contentVerticalMargin: CGFloat, segmentOnSelectionColour: UIColor, segmentOffSelectionColour: UIColor, titleOnSelectionColour: UIColor, titleOffSelectionColour: UIColor, titleOnSelectionFont: UIFont, titleOffSelectionFont: UIFont) { + public init(contentVerticalMargin: CGFloat, segmentOnSelectionColour: UIColor, segmentOffSelectionColour: UIColor, titleOnSelectionColour: UIColor, titleOffSelectionColour: UIColor, titleOnSelectionFont: UIFont, titleOffSelectionFont: UIFont, titleGravity: SMSTitleGravity?) { self.contentVerticalMargin = contentVerticalMargin @@ -65,5 +68,11 @@ open class SMSegmentAppearance { self.titleOffSelectionColour = titleOffSelectionColour self.titleOnSelectionFont = titleOnSelectionFont self.titleOffSelectionFont = titleOffSelectionFont + + if let gravity = titleGravity { + self.titleGravity = gravity + } else { + self.titleGravity = .right + } } } diff --git a/SMSegmentViewController/SMSegmentView/SMSegmentViewConstants.swift b/SMSegmentViewController/SMSegmentView/SMSegmentViewConstants.swift index 36a1b7f..4da652c 100644 --- a/SMSegmentViewController/SMSegmentView/SMSegmentViewConstants.swift +++ b/SMSegmentViewController/SMSegmentView/SMSegmentViewConstants.swift @@ -29,3 +29,10 @@ public enum SMSegmentOrganiseMode: Int { case horizontal case vertical } + +public enum SMSTitleGravity { + case right + case bottom + case left + case top +}