0

So I am trying to create the following effect using xcode swift.

I am trying to re-create the form bubble which contains the text fields and the text fields themselves, in the following style.

What I have tried so far:

Creating a UI View with curved borders, then using a transparent textfield and UILabels to indicate the field content.

I assume that the that must be a UItableview given the indent line but I am not sure how to style the tableview the same way. I assumed I can use the layer.cornerRadius as I did for the UIView but this doesn't seem to work.

Also is the entire view controller a UItableview controller or UICollectionView?

Any help on how to create the form as below would be appreciated.

enter image description here

Community
  • 1
  • 1
Rs Graphics
  • 183
  • 3
  • 14

3 Answers3

0

Using layer.cornerRadius for the whole tableview will not work. You should use a UITableviewController or a normal UIViewController which contains a tableView then divide your tableview into 3 sections

  • First section should be profile: no doubt about this section, border your cell the be the same as design

  • Second section should be personal information. 3 cells, each cell contain the text field. You can calculate and create border for the cell by corresponding position (top cell will be bordered top left & right, bottom cell will be bordered bottom left & right, otherwise no bordered)

  • Third section: no doubt about this, just one cell (switch account)

jacob
  • 1,024
  • 9
  • 14
  • Thanks for your suggestion, but how are you removing the insets for the cells. They still appear above and below. Also how would you pad this? Are you padding the inner container view? – Rs Graphics Sep 19 '19 at 11:16
  • There're a couple of ways to do that. You can either make leading & trailing constraint of tableview with supper view or inset inside your TableviewCell using this `self.contentView.frame = self.contentView.frame.inset(by: yourInset)` – jacob Sep 19 '19 at 11:33
0

In iOS 13 you can simply set the Style to Inset Grouped and the UITableView looks exactly like that - no additional changes necessary.

inexcitus
  • 2,471
  • 2
  • 26
  • 41
0

SWIFT Solution

Thanks to Paulo Silva

Step 1: You can simply create a swift file named it as 'CUIView' (or your own wish) and use following IBDesignable code inside it and save .

//
//  CUIView.swift
//  CustomUIView
//
//  Created by Paulo Silva on 23/08/2019.
//  Copyright © 2019 example. All rights reserved.
//

import UIKit
import UIKit
import CoreGraphics

@IBDesignable class CUIView: UIView {

    // MARK: - Private Variables -

    private let containerView = UIView()
    private var containerImageView = UIImageView()

    // MARK: - Public Attributes -

    @IBInspectable public var backgroundImage: UIImage? {
        get {
            return self.containerImageView.image
        }
        set {
//            addShadowColorFromBackgroundImage()
            self.containerImageView.image = newValue
        }
    }

    override open var backgroundColor: UIColor? {
        didSet(new) {
            if let color = new {
                containerView.backgroundColor = color
            }
            if backgroundColor != UIColor.clear { backgroundColor = UIColor.clear }
        }
    }

    @IBInspectable var borderColor: UIColor {
        get {
            return UIColor(cgColor: self.containerView.layer.borderColor!)
        }
        set {
            self.layer.borderColor = newValue.cgColor
            self.containerView.layer.borderColor = newValue.cgColor
        }
    }

    @IBInspectable var borderWidth: CGFloat {
        get {
            return self.containerView.layer.borderWidth
        }
        set {
            self.layer.borderWidth = newValue
            self.containerView.layer.borderWidth = newValue
        }
    }

    @IBInspectable var cornerRadius: CGFloat {
        get {
            return self.containerView.layer.cornerRadius
        }
        set {
            self.layer.cornerRadius = newValue
            self.containerView.layer.cornerRadius = newValue
        }
    }

    @IBInspectable var shadowOpacity: Float {
        get {
            return self.layer.shadowOpacity
        }
        set {
            self.layer.shadowOpacity = newValue
        }
    }

    @IBInspectable var shadowRadius: CGFloat {
        get {
            return self.layer.shadowRadius
        }
        set {
            self.layer.shadowRadius = newValue
        }
    }

    @IBInspectable var shadowOffset: CGSize {
        get {
            return self.layer.shadowOffset
        }
        set {
            self.layer.shadowOffset = newValue
        }
    }

    @IBInspectable var shadowColor: UIColor {
        get {
            return UIColor(cgColor: self.layer.shadowColor!)
        }
        set {
            self.layer.shadowColor = newValue.cgColor
        }
    }

//    @IBInspectable var shadowColorFormImage: Bool = false {
//        didSet {
//            addShadowColorFromBackgroundImage()
//        }
//    }

    // MARK: - Life Cycle -

    override init(frame: CGRect) {
        super.init(frame: frame)
        addViewLayoutSubViews()
        refreshViewLayout()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        addViewLayoutSubViews()
        refreshViewLayout()
    }

    override open func draw(_ rect: CGRect) {
        super.draw(rect)
        refreshViewLayout()
//        addShadowColorFromBackgroundImage()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        refreshViewLayout()
//        addShadowColorFromBackgroundImage()
    }

    // MARK: - Private Methods -

    private func refreshViewLayout() {
        // View
        self.clipsToBounds = true
        self.layer.masksToBounds = false
        self.layer.cornerRadius = cornerRadius

        // Shadow
        self.layer.shadowOpacity = shadowOpacity
        self.layer.shadowColor = shadowColor.cgColor
        self.layer.shadowOffset = shadowOffset
        self.layer.shadowRadius = shadowRadius

        // Container View
        self.containerView.layer.masksToBounds = true
        self.containerView.layer.cornerRadius = cornerRadius

        // Image View
        self.containerImageView.backgroundColor = UIColor.clear
        self.containerImageView.image = backgroundImage
        self.containerImageView.layer.cornerRadius = cornerRadius
        self.containerImageView.layer.masksToBounds = true
        self.containerImageView.clipsToBounds = true
        self.containerImageView.contentMode = .redraw
    }

    private func addViewLayoutSubViews() {
        // add subViews
        self.addSubview(self.containerView)
        self.containerView.addSubview(self.containerImageView)

        // add image constraints
        self.containerImageView.translatesAutoresizingMaskIntoConstraints = false
        self.containerImageView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        self.containerImageView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        self.containerImageView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        self.containerImageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

        // add view constraints
        self.containerView.translatesAutoresizingMaskIntoConstraints = false
        self.containerView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        self.containerView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        self.containerView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        self.containerView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }

//    private func addShadowColorFromBackgroundImage() {
//        // Get the averageColor from the image for set the Shadow Color
//        if shadowColorFormImage {
//            let week = self
//            DispatchQueue.main.async {
//                week.shadowColor = (week.containerImageView.image?.averageColor)!
//            }
//        }
//    }
}

extension UIImage {

    static func imageWithColor(tintColor: UIColor) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0)
        tintColor.setFill()
        UIRectFill(rect)
        let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()
        return image
    }

    func withBackground(color: UIColor, opaque: Bool = true) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, opaque, scale)
        guard let ctx = UIGraphicsGetCurrentContext() else { return self }
        defer { UIGraphicsEndImageContext() }
        let rect = CGRect(origin: .zero, size: size)
        ctx.setFillColor(color.cgColor)
        ctx.fill(rect)
        ctx.concatenate(CGAffineTransform(a: 1, b: 0, c: 0, d: -1, tx: 0, ty: size.height))
        ctx.draw(cgImage!, in: rect)
        return UIGraphicsGetImageFromCurrentImageContext() ?? self
    }

    var averageColor: UIColor? {
        guard let inputImage = CIImage(image: self) else { return nil }
        let extentVector = CIVector(x: inputImage.extent.origin.x, y: inputImage.extent.origin.y, z: inputImage.extent.size.width, w: inputImage.extent.size.height)

        guard let filter = CIFilter(name: "CIAreaAverage", parameters: [kCIInputImageKey: inputImage, kCIInputExtentKey: extentVector]) else { return nil }
        guard let outputImage = filter.outputImage else { return nil }

        var bitmap = [UInt8](repeating: 0, count: 4)
        let context = CIContext(options: [.workingColorSpace: kCFNull as Any])
        context.render(outputImage, toBitmap: &bitmap, rowBytes: 4, bounds: CGRect(x: 0, y: 0, width: 1, height: 1), format: .RGBA8, colorSpace: nil)

        return UIColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255)
    }
}

extension NSLayoutConstraint {
    func constraintWithMultiplier(_ multiplier: CGFloat) -> NSLayoutConstraint {
        return NSLayoutConstraint(item: self.firstItem!, attribute: self.firstAttribute, relatedBy: self.relation, toItem: self.secondItem, attribute: self.secondAttribute, multiplier: multiplier, constant: self.constant)
    }
}

extension UIScreen {

    enum SizeType: CGFloat {
        case unknown = 0.0
        case iPhone4 = 960.0
        case iPhone5 = 1136.0
        case iPhone6 = 1334.0
        case iPhone6Plus = 1920.0
    }

    var sizeType: SizeType {
        let height = nativeBounds.height
        guard let sizeType = SizeType(rawValue: height) else { return .unknown }
        return sizeType
    }
}

Step 2 : Connect your view associated class as 'CUIView' as following image

enter image description here

Step 3: Give corner radius and set background as like as following image .

enter image description here

For all the group textField and textfield you can use a view as parents view and associated class to get this outcome . For underline you can use simple view with minimum height to get desired design .

Nahid Raihan
  • 957
  • 1
  • 10
  • 20
  • Thanks for providing a solution but is this not just for the profile image (first cell)? I am trying to create the effect of the cells in the second section, the text fields. – Rs Graphics Sep 19 '19 at 11:15
  • This solution is not for tableview.you can achieve this just implementing only view . If you want to create it in tableview cell just under 2nd section for first and last cell take a view as background and implement following extension to get your desired view. For all others section just use given class for curve view. (Just sharing my idea, hope it will help). Link : https://stackoverflow.com/a/46542943/7643240 – Nahid Raihan Sep 19 '19 at 12:22