Making a Cell View in SwiftUI
Tags: swift, swiftui
Published: 2020-04-20 12:02:54

Let's make a View in SwiftUI which looks like a TableView / CollectionView Cell. All the code has been tested in Xcode Playgrounds, feel free to use it https://gist.github.com/Viranchee/87bfe6b39ae86bcc9b5b6f5d4b34d691

We will develop with Swift Playgrounds with Live View so as to easily test and debug. Open Xcode -> New Playgrounds -> Blank Playgrounds ->  (Indicate where to save the file). Now run your file using `Cmd+Shift+Enter` and you can see the output on right side of the screen. Since we will be rendering UI, we will make use of `PlaygroundSupport`. So go ahead, write these lines

``` swift
import SwiftUI
import PlaygroundSupport
```

To run any SwiftUI View inside Playground, we will use the `setLiveView` method.

``` swift
PlaygroundPage.current.setLiveView(Cell1())
```


Let us try to make a Cell with Image, Title and Subtitle
To view the live view, press `Cmd+Option+Enter`

``` swift
struct Cell1: View {
  var body: some View {
    HStack {
      Image(systemName: "music.house")
      VStack {
        Text("Title")
        Text("Subtitle")
      }
    }
  }
}
PlaygroundPage.current.setLiveView(Cell1())
```


 Now let us give a shadow to the view. We use the `background`, `stroke`, `shadow` and `foregroundColor` modifiers on the View.
 
 Note: ... means extra code which is same as the implementation in above snippet.
 
``` swift
HStack {
      ...
    }
    .background(
      RoundedRectangle(cornerRadius: 5)
        .stroke(Color.yellow)
        .shadow(color: .gray, radius: 2.5, x: 0.6, y: 0)
        .foregroundColor(.white)
    )
```

 Interesting!
 
 Now let us widen the view by increasing the text. Also let's fix our Image
 
 Let's use the `resizable`, `aspectRatio`, `frame` and `padding` modifiers on the Image and increase the length of our subtitle string

``` swift
HStack(spacing: 0) {
      Image(systemName: "music.house")
        .resizable()
        .aspectRatio(1, contentMode: .fit)
        .frame(height: 50)
        .padding()
      
      ...
    }
    .background(...)
```


 Great!
 
 Let's fix the Title Text and make it have a green background

 I will use the `bold` `italic` `lineLimit` `maximumScaleFactor` `padding` `background` `foregroundColor` modifiers here

``` swift
VStack(alignment: .leading) {
        Text("Title")
          .bold()
          .italic()
          .lineLimit(1)
          .minimumScaleFactor(0.8)
          .padding(.horizontal, 10)
          .padding(.vertical, 2)
          .background(
            Capsule()
              .foregroundColor(.green)
        )
          .padding(.bottom, 5)
        ...
```

 So far so good. Now let's modify the Subtitle Text

 I will use these View Modifiers: `lineLimit` `multilineTextAlignment` `truncationMode` and a `fixedSize` modifier here.
 
``` swift
Text("A long subtitle which extends more than a line")
          .lineLimit(2)
          .multilineTextAlignment(.leading)
          .truncationMode(.tail)
          .fixedSize(horizontal: false, vertical: true)
```

This completes much of our Cell View. Now, let us check how the View behaves under different circumstances, viz. different lengths of Title and Subtitle. To simulate the different sizes live, we will use the Slider which looks like such

``` swift
struct SliderView: View {
  @State private var titleLength: CGFloat = 1  
  
  var body: some View {
        Text(String.init(repeating: "T", count: Int(self.titleLength)))
        Text("Title length")
        Slider(value: $titleLength, in: 1...100) {
// This Text is for Accessibility
          Text("Title")
}
```

Integrating the slider to control the Text length looks like such in code and output:

``` swift
struct Cell6: View {
  @State private var titleLength: CGFloat = 1
  @State private var subtitleLength: CGFloat = 1
  
  
  var body: some View {
    VStack {

      
      HStack(spacing: 0) {
        Image(systemName: "music.house")
          .resizable()
          .aspectRatio(1, contentMode: .fit)
          .frame(height: 50)
          .padding()
        
        VStack(alignment: .leading) {
          Text(String.init(repeating: "T", count: Int(self.titleLength)))
            .bold()
            .italic()
            .lineLimit(1)
            .minimumScaleFactor(0.8)
            .padding(.horizontal, 10)
            .padding(.vertical, 2)
            .background(
              Capsule()
                .foregroundColor(.green)
          )
            .padding(.bottom, 5)
          Text(String.init(repeating: "S", count: Int(self.subtitleLength)))
            .lineLimit(2)
            .multilineTextAlignment(.leading)
            .truncationMode(.tail)
            .fixedSize(horizontal: false, vertical: true)
            .minimumScaleFactor(0.7)
        }
      }
      .background(
        RoundedRectangle(cornerRadius: 5)
          .stroke(Color.yellow)
          .shadow(color: .gray, radius: 2.5, x: 0.6, y: 0)
          .foregroundColor(.white)
      )
      
      HStack {
        Text("Title length")
        Slider(value: $titleLength, in: 1...40) {
          Text("Title")
        }
      }
      
      HStack {
        Text("Subtitle length")
        Slider(value: $subtitleLength, in: 1...100) {
          Text("Subtitle")
        }
      }
    }
  }
}

PlaygroundPage.current.setLiveView(Cell6())
```

Finally, we have crafted a SwiftUI View of our requirements and tested it with variety of input string size.

Credits: 

- www.pointfree.co
- www.objc.io
- www.bigmountainstudio.com
- www.raywenderlich.com
- www.swiftwithmajid.com