<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Rajdeep Kwatra on Medium]]></title>
        <description><![CDATA[Stories by Rajdeep Kwatra on Medium]]></description>
        <link>https://medium.com/@rkwatra?source=rss-cee883b2eeac------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*YwYdPKQmrXC_pjYR8qN0Hw.png</url>
            <title>Stories by Rajdeep Kwatra on Medium</title>
            <link>https://medium.com/@rkwatra?source=rss-cee883b2eeac------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 13 Jul 2026 16:39:02 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@rkwatra/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Mentions in UITextView using Proton Editor]]></title>
            <link>https://medium.com/@rkwatra/mentions-in-uitextview-using-proton-editor-c73072bf65a8?source=rss-cee883b2eeac------2</link>
            <guid isPermaLink="false">https://medium.com/p/c73072bf65a8</guid>
            <dc:creator><![CDATA[Rajdeep Kwatra]]></dc:creator>
            <pubDate>Fri, 26 Aug 2022 07:46:06 GMT</pubDate>
            <atom:updated>2022-08-26T07:46:06.380Z</atom:updated>
            <content:encoded><![CDATA[<p>Mentioning someone is one of the most common feature in social/work apps these days, and it looks a trivial task to implement the same too — or at least, one would hope so. In a typical app, there would be a UITextView in which users may type the content, and also mention someone. However, as you might know, to get a simple mention in a UITextView is not as simple after all. This is one of the motivations of extending the Open-Source library, <a href="https://github.com/rajdeep/proton">Proton</a> to add support for a better background than what is provided by iOS natively.</p><p>Let’s see what options do iOS provides and what can we build on top of it to not only make user experience better, but developer experience too.</p><h3>Plain vanilla Mentions</h3><p>The simplest approach to adding a specific UI treatment for mentions in UITextView would be to use NSAttributedString with background attribute. The code looks pretty simple to add background to given range of text:</p><pre><strong>let</strong> mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br>     .backgroundColor: UIColor.systemBlue,<br>     .foregroundColor: UIColor.white<br>])</pre><pre>editor.attributedText = mention</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/730/1*PQZzOhFxxq7_7bPLBZ3PYg.png" /></figure><p>However, as you can see, it looks pretty bland and there’s not much that we can do with just attributes. For instance, at the very least, it would be desirable to have rounded corners for the mention text. Unfortunately, it is not doable without really changing how backgrounds are drawn in NSLayoutManager.</p><h3>Extending UITextView and NSAttributedString</h3><p>Mentions is one of initial requirements that I looked at when I started working on <a href="https://github.com/rajdeep/proton">Proton</a>. I always felt that background style in NSAttributedString is severely limited in terms of what developers can do with it and hence I developed my own version of background style attribute, appropriately called backgroundStyle in <a href="https://github.com/rajdeep/proton">Proton</a>. <a href="https://github.com/rajdeep/proton">Proton</a> just extends a UITextView and NSAttributedString to add powerful new features, and a more intuitive API for existing features.</p><p>Let’s see how we can utilize backgroundStyle along with a few other attributes to build a perfect mention:</p><p><strong>Starting off</strong></p><p>Just like background example above, we can use backgroundStyle to get exact same output:</p><pre>let mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br><strong>    .backgroundStyle: BackgroundStyle(color: .systemBlue),</strong><br>    .foregroundColor: UIColor.white<br>])<br>editor.attributedText = mention</pre><p><strong>Adding style</strong></p><p>Unlike background attribute though, it is just as simple to add rounding to the backgroundStyle:</p><pre>let mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br>   .backgroundStyle: <br>      BackgroundStyle(color: .systemBlue, <br>      <strong>roundedCornerStyle: .relative(percent: 50)),</strong><br>   .foregroundColor: UIColor.white<br>])<br>editor.attributedText = mention</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/730/1*HGIJWD1k0lQZXKeEUTfsWQ.png" /></figure><p>roundedCornersStyle may be a relative percentage of height of text to get perfectly rounded corners irrespective of text size, or it can have a absolute value for corner radius.</p><p>Not only that, if you wish, you can add also shadow and borders:</p><pre><strong>let</strong> mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br>   .backgroundStyle: <br>      BackgroundStyle(color: .systemBlue,<br>      roundedCornerStyle: .relative(percent: 50),<br><strong>      border: BorderStyle(lineWidth: 1, color: .systemRed),<br>      shadow: ShadowStyle(color: .systemGray,<br>         offset: CGSize(width: 1, height: 1),blur: 2)),<br></strong>   .foregroundColor: UIColor.white<br>])<br>editor.attributedText = mention</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/730/1*lfT48WypIfOZp36m3uic5w.png" /></figure><p><strong>What about editing</strong></p><p>Editing text with attributes like that for mentions bring along a whole new set of issues because of how attributes are treated in UITextView.</p><p><strong><em>Bleeding attributes</em></strong></p><p>This is one of the issues you might not realise until you see one. When a set of attributes are applied to string, these are automatically added to typingAttributes. This means, if you have applied background or backgroundStyle or for that matter any other attribute, it will automatically be carried forward in the following range:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*aitpvaTWY2cAFCA2.gif" /></figure><p>Of course, this is not desirable. This can be fixed very easily in <a href="https://github.com/rajdeep/proton">Proton</a> by using another attribute called lockedAttributes. Any attribute that is not desired to be carry forward (in this case, backgroundStyle and foregroundColor), can be added to lockedAttribute to prevent bleeding these into the following range.</p><pre>let mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br>   .backgroundStyle: <br>      BackgroundStyle(color: .systemBlue,<br>      roundedCornerStyle: .relative(percent: 50)),<br>   .foregroundColor: UIColor.white,<br><strong>   .lockedAttributes: <br>   [<br>        NSAttributedString.Key.foregroundColor,         <br>       .backgroundStyle<br>   ]<br></strong>])<br>editor.attributedText = mention</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*7S7Kbj7_CG871EZv.gif" /></figure><p><strong><em>Partial deletion</em></strong></p><p>Another issue that this implementation would show is, that user can delete part of the mention. This is because it’s still just text in the UITextView which is editable.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*RWvDUrh43s7LOiu9.gif" /></figure><p>A typical requirement would be that if a part of mention is deleted, the entire mention should be removed. This can be solved by adding yet another attribute called textBlock to the range. This makes the entire range of text with this attribute act as a single block i.e. you can only delete it as a single unit, and you can not have the cursor anywhere in the middle of it:</p><pre><strong>let</strong> mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br>   .backgroundStyle: <br>      BackgroundStyle(color: .systemBlue,<br>      roundedCornerStyle: .relative(percent: 50)),<br>    .foregroundColor: UIColor.white,<br>    .lockedAttributes: <br>      [<br>           NSAttributedString.Key.foregroundColor,         <br>          .backgroundStyle<br>      ],<br><strong>     .textBlock: true<br></strong>])<br>editor.attributedText = mention</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*_Uf8c6tHXxH_f8I4.gif" /></figure><p><strong><em>Wrapping</em></strong></p><p>As with any other part of text, a mention may also be long enough that it wraps to next line. By default, it will show up as 2 capsules.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*06ibtVHzTF0McoiH.gif" /></figure><p>However, we may want to show the wrapping as a continuity. This can be achieved by providing another argument, hasSquaredOffJoins to backgroundStyle. This ensures that at for all the continuous ranges, having wrapped text, the inner edges would be squared off giving an impression that it is continuing from previous line:</p><pre>let mention = NSAttributedString(string: &quot;@rajdeep&quot;, attributes: [<br>   .backgroundStyle: <br>      BackgroundStyle(color: .systemBlue,<br>      roundedCornerStyle: .relative(percent: 50),<br>      <strong>hasSquaredOffJoins: true</strong>),<br>    .foregroundColor: UIColor.white,<br>    .lockedAttributes: <br>      [<br>           NSAttributedString.Key.foregroundColor,         <br>          .backgroundStyle<br>       ],<br>     .textBlock: true<strong><br></strong>])<br>editor.attributedText = mention</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/600/0*2TcL4mbcHUIvFFkl.gif" /></figure><p>And as simple as that, we have a mention that works just as we expect in an editable text view.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c73072bf65a8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Editable Grid in iOS]]></title>
            <link>https://medium.com/@rkwatra/editable-grid-in-ios-79f11f0de6c0?source=rss-cee883b2eeac------2</link>
            <guid isPermaLink="false">https://medium.com/p/79f11f0de6c0</guid>
            <dc:creator><![CDATA[Rajdeep Kwatra]]></dc:creator>
            <pubDate>Thu, 11 Aug 2022 09:03:34 GMT</pubDate>
            <atom:updated>2022-08-11T09:03:34.662Z</atom:updated>
            <content:encoded><![CDATA[<h3>Introduction</h3><blockquote>This article is focussed on using open-source library <a href="https://github.com/rajdeep/proton">Proton</a>. If you have not yet checked it out, you may read more about it in stories in <a href="https://medium.com/@rkwatra/list/proton-0d50aef77eb4">this list</a>.</blockquote><p>Ever since I have started working on Proton, I have been asked if it is just as easy to create a Tabular structure in Proton Editor, as it is to create another type of content, like a Panel or an Expandable content. And my answer would always be, yes- of course! However, I wasn’t able to make time to try it out, until now.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vuH5gwZhvW0BhYtxh3ak5w.gif" /></figure><p>This article talks about my experience of creating a tabular structure that can be hosted within the Editor. Each of the cells further contain the Editor itself, which makes it possible to put any type of content in a cell, including another table. Read on to get to know more about the implementation.</p><h3>Initial exploration</h3><p>My original idea was to use <a href="https://developer.apple.com/documentation/uikit/uicollectionview">UICollectionView</a> with custom layout. On the face of it, it seemed pretty achievable and it probably still is if we only consider the rendering part of the Table. However, since Tables are supposed to be editable as well, it was proven early on that that cell resizing, as content is typed, would be difficult if not impossible in a UICollectionView. Moreover, I also had in mind that eventually there needs to be support to merge/split cells as well as resize columns. Looking at all these requirements, I dropped the idea of using a UICollectionView after just a couple of spikes.</p><h3>Final Implementation</h3><p>The failed spikes using UICollectionView made it clear to me that the UI of Table needs to be as dumb as possible, and responsible only for rendering Table cells based on some data. The core logic of cells, sizes, merge/split concern etc. all need to be outside the Table UI. Hence, I created a simple data structure that works off a collection of columns widths and row heights, and generates the frames for each of the cell inside the table.</p><p>Table in Proton is called GridView to avoid confusion with any existing iOS component, particularly UITableView. GridView constitutes of following components:</p><ul><li>Grid: Engine behind rendering of the GridView. Grid holds a collection of widths of each of the columns and heights for all the rows in separate array, ordered by respective indexes. It works off a CellStore that holds a collection of cell. GridView is responsible for logic of generating the frames of the cells, controlling the merging/splitting of cells and also additional logic/validating around adding/deleting rows and columns. This is internal to Proton.</li><li>GridCellStore: Holds a collection of GridCell and is responsible for actual deleting and addition of cells including logic to adjust the row/column indexes following addition or deletion of row/column. This is internal to Proton.</li><li>GridCell: A simple UIView that hosts a Proton EditorView and provides features like selection and customizing content like font, text color and background color. This is a public class.</li><li>GridContentView: A scrollable view that is uses Grid to generate and layout cells in the Table. It also provides the gesture support for selecting cells and resizing columns. This is internal to Proton.</li><li>GridView: Public class that encompasses all the aforementioned classes to provide a UIView that can then be used in an Attachment in Proton to be used within the Editor.</li></ul><h3>Implementation Overview</h3><p><strong>Generating cells:</strong></p><p>One of the most interesting challenge was how to generate the cells such that they are able to be resized, merged and split back without involving complex logic or operations. There are multiple simple parts that come together to make one complex operation possible:</p><ul><li>Each cell has an associated array of column and row indexes. Merging cells means concatenating the rows and/or columns in these arrays, whereas Splitting would mean creating new cells with individual indexes for rows and columns.</li><li>Information about Width and Height of each of the cell is not responsibility of the cell. In fact, cell only gets its frame whenever layout of grid takes place. A seperate object, Grid, holds the collection of widths for each of the columns and heights for each of the rows. This allows to calculate frame of the cell based on its index and column width configuration, which can be fixed or fractional (based on container).</li><li>When a new row or column is added, the new height/width is appended to the row or column collection at the assigned index.</li><li>Deleting a row or column deletes the item at given index from row heights or column widths.</li><li>Having the row heights and column widths separate allows to simplify relayout calculations by a great degree. Frames are always calculated based on these collections, and relayout only requires updating these collections and rest all happens automatically.</li></ul><p><strong>Rendering grid:</strong></p><p>Rendering the grid on the UI is another place where a very simple approach is used. Each of the GridCell is a UIView. Typically, adjacent views have autolayout constraints amongst each other. This would have been relatively straightforward with a simple table without merge/split behaviour. However, with operations like delete/add of rows and columns and merging/splitting of cells, it would have been very complex to maintain.</p><p>In order to simplify the approach, each of the cells is anchored from top and leading edge of the GridContentView which is a scrollable container for the cells. Each of the cells is laid out in reference to these edges. This means that the layout is actually based on the frame of the cell as calculated while generating the cells and will always work irrespective of merged cells placements with respect to other cells around it.</p><p>Following illustration tries to highlight the approach taken to render the grid:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hsB9sUuorjBiS-xXzm_UJA.png" /><figcaption>Cell layout in GridView</figcaption></figure><h3>Merging/Splitting rows and columns:</h3><p>As mentioned above, merging and splitting only requires adding column or row indexes in the collection information held by the cell. This does not affect the row height and column width collection held by the Grid.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aPj-0d0kcIYWDdxRfAuuWA.gif" /></figure><p>Following are the operations that occur when a cell is merged with another:</p><ul><li>Validate if the cells can be merged — for cells to be mergable, the aggregate frame of selected cells needs to be a rectangle without any holes in it.</li><li>First cell is taken and it’s rows and columns collection are updated to include rows and columns of all the other cells passed in. Merge operation can be performed on any number of cells as long as the validation passes.</li><li>The actual cell instances all cells other than first one are deleted from the CellStore which holds collection of all the cells.</li><li>Once the cell information is updated, layout is invalidated which invokes relayout of grid:</li><li>Frame of each of the cell is calculated based on container size.</li><li>Top and Leading anchor constraints are updated based on the new frame values for the cells.</li><li>Intrinsic content size is invalidated which updates the new information on the UI.</li></ul><p>Split operation works pretty much the same but instead of adding row and column information in the cells, the cell’s row and column information is broken down to new cells with each having one index for row and columns. Also, newly generated cells are then added to the CellStore and new constraints are added for the top and leading anchors from container.</p><p>Relayout code for grid stays exactly the same when rendering grid for the first time, and also when merging/splitting and adding/deleting rows and columns.</p><h3>Further exploration</h3><p>To explore further, feel free to take a look at the <a href="https://github.com/rajdeep/proton/tree/main/Proton/Sources/Swift/Grid">Grid code</a> in <a href="https://github.com/rajdeep/proton">Proton</a>. The implementation is pretty straightforward and hopefully, will be easy to follow. A good starting point would be <a href="https://rajdeep.github.io/proton/Classes/GridView.html">this documentation</a>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*AbVGWDLVeMganQB6JgZ7zw.gif" /></figure><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=79f11f0de6c0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Background with rounded corners in UITextView]]></title>
            <link>https://levelup.gitconnected.com/background-with-rounded-corners-in-uitextview-1c095c708d14?source=rss-cee883b2eeac------2</link>
            <guid isPermaLink="false">https://medium.com/p/1c095c708d14</guid>
            <category><![CDATA[uitextview]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[background]]></category>
            <category><![CDATA[proton]]></category>
            <dc:creator><![CDATA[Rajdeep Kwatra]]></dc:creator>
            <pubDate>Sun, 19 Jul 2020 23:34:32 GMT</pubDate>
            <atom:updated>2020-07-19T23:34:32.058Z</atom:updated>
            <content:encoded><![CDATA[<p>I have had the opportunity to learn so many things while working on <a href="https://github.com/rajdeep/proton/">Proton</a>. Just as much as I like sharing my code, I also enjoy talking about the challenges and the wins. This article focuses on yet another feature in <a href="https://github.com/rajdeep/proton/">Proton</a> which, I believe, should have been available out of the box in iOS. If you are new here and before diving into the details, would like to know more about <a href="https://github.com/rajdeep/proton/">Proton</a>, <a href="https://levelup.gitconnected.com/building-a-native-editor-for-ios-968ff9bc6e0c">Building a native editor for iOS</a> is a good place to start.</p><h3>Text with background</h3><p>Often there are times when we want to add background to the text in a text view. The most simplest, and probably best, approach is to use <a href="https://developer.apple.com/documentation/foundation/nsattributedstring/key/1528791-backgroundcolor">backgroundColor</a> attribute. You can provide any UIColor to a given range, and iOS takes care of rendering that color in the background of the text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*wOmbb7jAISGE0KQYl-Wxaw.png" /><figcaption>Text with .backgroundColor attribute</figcaption></figure><p>The only code you need is to add attribute backgroundColor: UIColor.cyan to the list of NSAttributedString.Key in the attributedText property of UITextView. While this works for most cases, it may feel too vanilla. You might want a fancier formatting like adding shadows or borders. At the very least, it is very likely that you would want rounded corners to the background. Unfortunately, none of these properties may be modified by just using attributes.</p><h3>Better backgrounds</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*47_BkChF6mpSnqOSBGaRQQ.png" /></figure><p>One of the principles I am following with <a href="https://github.com/rajdeep/proton/">Proton</a> is to provide all that, we as developers, might want to customize and yet keep those customizations natural. What I mean is that all the customizations that you might want to do, should ideally not take anything more than adding an attribute with required information. For e.g. if you want to add lists to a UITextView, it should be as simple as adding a .listItem attribute to the range of text. You can read about my adventures with lists in <a href="https://medium.com/dev-genius/lists-in-uitextview-756fe2b1407a">Lists in UITextView</a>. With <a href="https://github.com/rajdeep/proton/">Proton</a>, you can add an attribute, very similar to backgroundColor, and achieve the following:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*NCHl1YutjoDUXL9nDWchRA.png" /><figcaption>Background with rounded corners</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*FbJeyBPMuJstvHYPwX2kLA.png" /><figcaption>Rounded corners with shadows</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*DnnsJY4s-TgOsL5NQYKDcA.png" /><figcaption>Background with borders only</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*J9C6d8UjvakfSkBhg2xJBQ.png" /><figcaption>Shadow, border and rounded corners</figcaption></figure><p>The only code you need to add is:</p><pre>let style = BackgroundStyle(color: .green, cornerRadius: 5, <br>border: BorderStyle(lineWidth: 1, color: UIColor.blue),  <br>shadow: ShadowStyle(color: .gray, offset: CGSize(width: 2, height: 2), blur: 3))</pre><pre>editor.addAttribute(.backgroundStyle, value: style, at: editor.selectedRange)</pre><p>editor is the <a href="https://github.com/rajdeep/proton/">Proton</a> counterpart for UITextView. Besides other features, it provides simple API to manipulate attributes.</p><h3>Under the hood</h3><p>If you want to understand how this has been achieved in <a href="https://github.com/rajdeep/proton/">Proton</a>, please read on.</p><p>The layout and drawing of text is managed by <a href="https://developer.apple.com/documentation/uikit/nslayoutmanager">NSLayoutManager</a>. It provides two functions that can be overridden to achieve the desired behaviour:</p><h4>Initial approach</h4><p>The first approach I tried was using <a href="https://developer.apple.com/documentation/uikit/nslayoutmanager/1403161-fillbackgroundrectarray">fillBackgroundRectArray</a>. This function provides a finer control over drawing the background for the ranges with .backgroundColor attribute. This function gets invoked with all the rectangles defining the range with background color.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/99a95bcd47c5e874a83a8f0b51e2ddef/href">https://medium.com/media/99a95bcd47c5e874a83a8f0b51e2ddef/href</a></iframe><p>This approach works, but depending upon how content is added, <a href="https://developer.apple.com/documentation/uikit/nslayoutmanager/1403161-fillbackgroundrectarray">fillBackgroundRectArray</a> may be called multiple times even for the text that is in the same line. This results in rendering rounded corners based on words instead of lines of text:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*oHLmIPzjWJXm4fB_V-kg9g.png" /></figure><p>If the content is pasted instead of being typed, the background is drawn as expected with no visible rounding per word as we see above.</p><h4>Final approach</h4><p>Spending a little more time with NSLayoutManager, I figured out that using <a href="https://developer.apple.com/documentation/uikit/nslayoutmanager/1402949-drawbackground">drawBackground</a> is a better option. Using similar code as above, you can achieve better results.</p><p>In <a href="https://github.com/rajdeep/proton/">Proton</a>, I added additional logic to calculate the rounded corners based on each of the lines that are overlapping and also used a trick that ensures that when there are borders, the borders are only drawn on outer edges of the rectangles with background.</p><p>The initial version with all the selected range looked like the following where the corners are rounded at outer edges, but there is still bottom line of the first rectangle that is causing this to appear as two separate background rectangles.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*MdBaOVhMkT4iBVkGo8gwBg.png" /></figure><p>Using some simple logic, I was able to calculate the overlapping line, which is shown in yellow color below:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*3XLwGW6IqjxMdPtwWw5NAw.png" /></figure><p>Once the overlapping line is identified, the only other thing that is left is to use the same color for the line as that for the background, so that the line disappears:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/684/1*qFu34eRcV_b70GzQStPa2g.png" /></figure><h4>One more thing</h4><p>With all the calculations that are put in place to draw background with rounded corners, it also helps drawing the background dynamically where it merges and splits the background based on the range of text having the backgroundStyle applied:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/672/1*pICxqEeQEYigWeojl8Ms7g.gif" /></figure><p>I hope you enjoyed reading about this just as much as I enjoyed developing this feature in <a href="https://github.com/rajdeep/proton/">Proton</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1c095c708d14" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/background-with-rounded-corners-in-uitextview-1c095c708d14">Background with rounded corners in UITextView</a> was originally published in <a href="https://levelup.gitconnected.com">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Building a native editor for iOS]]></title>
            <link>https://levelup.gitconnected.com/building-a-native-editor-for-ios-968ff9bc6e0c?source=rss-cee883b2eeac------2</link>
            <guid isPermaLink="false">https://medium.com/p/968ff9bc6e0c</guid>
            <category><![CDATA[macos-catalyst]]></category>
            <category><![CDATA[open-source]]></category>
            <category><![CDATA[rich-text-editor]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Rajdeep Kwatra]]></dc:creator>
            <pubDate>Wed, 08 Jul 2020 11:46:25 GMT</pubDate>
            <atom:updated>2020-07-17T12:32:17.279Z</atom:updated>
            <content:encoded><![CDATA[<h3>Prologue</h3><p>I have always been fascinated with the great Open Source community that all of us software developers enjoy. There have been some great frameworks which have come out of people’s passion for solving a problem or making a great thing even better. I have used so many open source frameworks throughout my career as a software developer and have always wanted to contribute back. However, I was not able to come up with a good problem to solve, until now. You already know from the heading — it’s a full fledged completely native iOS editor framework.</p><p>We use rich text editors almost all the time without even realizing — like I am using an editor on Medium to write this story. I am using features like adding headings, links, images etc. but I am thinking about the content, not about how to add all these formatting. In my experience as a developer, I have found numerous web based Rich Text Editors, however not many as feature rich on iOS. So that’s why, I thought of building one.</p><h3>Introduction</h3><p>It always seemed like a very interesting technical challenge to solve to be able to come up with a capable and extensible editor on iOS. While it is possible to have a web based editor running on iOS and which just works there are a few things which are not as simple to handle in a non-native technology. My inclination towards native editor is driven by the fact that there are so many native features like Dynamic Font sizing and theming which are relatively easy to implement in native but can be very challenging when using web based technologies as a native solution (hybrid).</p><h3>Requirements</h3><p>Instead of creating a Rich Text Editor that can just serve as a drag-drop component, I wanted to come up with a framework that can help any one create a Rich Text Editor. The primary reason for this was that I wanted people to be able to add any feature that they need and not be driven or restricted by what is provided out of the box.</p><p>At a high level, the requirements that I wanted to cater were:</p><ul><li>Be a standalone component — in its simplest form, it should be a straight replacement of UITextView and in its most complex form, it should be able to handle any functionality that can be expected out of a capable rich text editor.</li><li>Should be extensible to support adding any view as content in the Editor such that it flows with the text.</li><li>Resizing of content views should automatically resize the containing Editor and support this to nth nesting level.</li><li>Should support extending the appearance of text as the content is typed — for e.g. changing text as it is typed using mark-up syntax or highlighting as typeahead character is entered — and yet, not be aware of any of these requirements directly.</li><li>Should allow for working on multiple editors through the same toolbar based on where the focus is.</li><li>Respect the bounds of the container i.e. resize to change when the device orientation changes.</li><li>Support a default font and styling like alignment and head indentation.</li><li>And of course, support all this on macOS Catalyst as well with almost no additional effort.</li></ul><h3>A framework is born</h3><p>With all these requirements in my mind, I started working on a framework and in about 3 months, I had a working version that catered to almost all the initial requirements. I called it <a href="https://github.com/rajdeep/proton/">Proton</a> — something that brings about positivity for developers that use it and for their end users using the great apps by these developers!</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*47_BkChF6mpSnqOSBGaRQQ.png" /></figure><p><a href="https://github.com/rajdeep/proton/">Proton</a> is composed of following key components:</p><h4>Editor</h4><p>To allow for all the points listed above, Editor introduces some key concepts. These concepts allow for extending the Editor at various levels — even in ways that I have not explicitly designed the Editor framework for as we will see later.</p><p><strong><em>* </em></strong><em>All screen captures shown below are from iOS simulator.</em></p><h4>Attachments</h4><p>One of the most basic concepts of Editor is Attachments. Attachments are what allow Editor to have any view within Editor text. With support of Attachments, Editor can contain an emoji, a panel or even a table as long as it can be represented as a UIView. An Editor can contain another Editor as well.</p><p>There are five types of Attachments which are provided out of the box:</p><ul><li><strong>Matching content:</strong> An attachment that automatically resizes based on the size of the content i.e. as the content changes, the size of attachment changes to match that.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*EOWoYrv-SabMSmQsbst3Ww.gif" /><figcaption>Attachment matching content size</figcaption></figure><ul><li><strong>Full width:</strong> An attachment that always takes the full width available in its container. If the width of container changes, the width of attachment would change to match that.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*RtQdpe6Qa7BU8vztHa3wQA.gif" /><figcaption>Attachment width matches container width</figcaption></figure><ul><li><strong>Fixed width:</strong> An attachment that always respects a configurable fixed width.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*PSXdwAhV6Mz20k-r7785mw.gif" /><figcaption>A fixed width attachment</figcaption></figure><ul><li><strong>Width range:</strong> An attachment that always retains a minimum width even when empty but only grows up to the given maximum width.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*pIixRizS97hryzSq1VvOxg.gif" /><figcaption>A attachment with min and max width</figcaption></figure><ul><li><strong>Percent width: </strong>An attachment that always takes up a certain percentage width of the container. As the container size changes, the size of attachment should change to respect the percentage that is used to create the attachment.</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*PWRuRbJ6oWW6nMiR0yVLjQ.gif" /></figure><p>All these examples use a text view that is added as an attachment in the main editor. You can add any view inside attachment and apply the sizing rule that fits best for your scenario.</p><p>Creating any of these attachments is just a few lines of code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/df51f5a422ca5b64266030ea9a446890/href">https://medium.com/media/df51f5a422ca5b64266030ea9a446890/href</a></iframe><h4>Commands</h4><p>Besides adding different kinds of views as content, an editor should allow to change content attributes as well as contents based on user interaction. For e.g. a user might want to select some text to make it bold or select some text and put that in a Panel. All such interactions which change the appearance attributes of the text in the editor or the content in the Editor based on user’s interaction are made possible by Commands.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*PjEeM4MxFNugNP2Ynd9ulg.gif" /><figcaption>Making text bold on clicking a button</figcaption></figure><p>A command can be executed directly on a given Editor or be passed on to Command Executor so that it is automatically run on the Editor that has the focus.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*pFOXOJArsnNCGZo0p0dKlw.gif" /><figcaption>Executing command on the editor in focus</figcaption></figure><p><a href="https://github.com/rajdeep/proton/">Proton</a> allows you to add your own commands, that you can add logic to, to carry out tasks like the ones shown above. For text formatting, <a href="https://github.com/rajdeep/proton/">Proton</a> already provide a base class that can be extended to add any <a href="https://developer.apple.com/documentation/uikit/uifontdescriptor/symbolictraits">Font Traits</a> supported by iOS.</p><p>Creating a command for making text bold is as simple as:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e8df7f3b08960fc191f2f5474d816ec4/href">https://medium.com/media/e8df7f3b08960fc191f2f5474d816ec4/href</a></iframe><p>Executing a command is just another line of code which can be invoked on click of a button:</p><pre>BoldCommand().execute(on: editor)</pre><p>Based on your logic, a command can work on the selected text or the entire Editor.</p><h4>Command Executor</h4><p>A Command Executor allows you to execute the given command on any Editor that has the focus. This comes in handy if you have an attachment that contains an editor, and the command can be executed on both the main editor containing the attachment as well as the editor inside the attachment. It abstracts away the complexity of knowing which Editor the user is trying to run the command on. This is made possible by another concept called Context which binds the Editor to the Command Executor. All the Editors sharing the same context as the Command Executor will automatically be linked with Command Executor.</p><h4>Context</h4><p>A Context acts like a key to link between Command Executor and an Editor. A Context allows you to link multiple Editors with the same Command Executor. This can be useful in the scenarios where you have multiple Toolbars acting on one or more Editors i.e. Editor contained inside an Attachments and then added to another Editor.</p><h4>Text Processors</h4><p>An editor does not only require making changes on explicit user interactions, but also as the user is changing the text. One such example is a Type-ahead where the text is highlighted in blue as the trigger character is entered. Another example is when a user tries to use markup syntax to format the text as they type opening and closing markers.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*cR8LiVAVdp0cF4IkTUBNGg.gif" /><figcaption>Example of Markdown TextProcessor</figcaption></figure><p>Text Processors also allow setting the priority. An Editor may register multiple Text Processors. Whenever the text changes inside the Editor, all the registered Text Processors get an opportunity to change the text or add attributes as required.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/706/1*4sk8kAuRyVzq4OGLgPiBrw.gif" /><figcaption>Mentions TextProcessor relaying typed text</figcaption></figure><p>Text Processors are given the opportunity to change text/attributes based on their respective priorities. The priority runs from High to Low and all the subsequent processors gets the text as changed by the processor that ran before it i.e. a processor will always get the updated text. This also allows to combine the effects from multiple Text Processors, if required. Besides high, medium and low, the Text Processor also has a priority called exclusive. If an Exclusive Text Processor is run, it prevents all the other Processors from executing. Instead, it notifies the other Processor that their processing has been interrupted so that the Processors can run any cleanup code, if required.</p><p>Just like Commands, you can add your own text processors to carry out the functionality like ones shown above.</p><h4>Renderer</h4><p>A Renderer always goes hand in hand with the Editor. Relation between Renderer and Editor is just same as that of UILabel and UITextView — it’s just a lot more powerful. In its simplest form, a Renderer is nothing but a read-only Editor. However, to provide an API that is easy to use and looks natural, Renderer encapsulated Editor and exposes its own set of features which are more suited to a Renderer. For e.g. having a TextProcessor would not make sense in the Renderer since the user cannot really type content inside the Renderer. However, Commands may be required to provide functionality like highlighting the text in the Renderer.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/706/1*_0EB_-5PzLfgUocsD7NLjw.gif" /><figcaption>Highlight text based on selection</figcaption></figure><p>By virtue of the Editor, Renderer gains features like inspecting contents and scrolling to a given range. Both these capabilities can be used to create a feature like Find text.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/710/1*Sy1z0MUowkP2_9xUKpUCQw.gif" /><figcaption>Find text and scroll to content</figcaption></figure><p>Creating this command is just another few lines — thanks to the helper functions that <a href="https://github.com/rajdeep/proton/">Proton</a> provides:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/33d1eb1f0964c55a36863f77c56b1316/href">https://medium.com/media/33d1eb1f0964c55a36863f77c56b1316/href</a></iframe><p>A recent addition to <a href="https://github.com/rajdeep/proton/">Proton</a> is ListCommand and ListTextProcessor that takes care of all the formatting that you might want to have for creating lists in ` UITextView. To read more about lists, head over to <a href="https://medium.com/dev-genius/lists-in-uitextview-756fe2b1407a">Lists in UITextView.</a></p><h3>And the story continues…</h3><p>I plan to continue evolving <a href="https://github.com/rajdeep/proton/">Proton</a> and add more features that I already have in my mind. I hope you have enjoyed reading about it and ready to take <a href="https://github.com/rajdeep/proton/">Proton</a> out for a spin.</p><p>I would love to hear from you. Please feel free to share your comments/thoughts and any feature requests in comments section.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=968ff9bc6e0c" width="1" height="1" alt=""><hr><p><a href="https://levelup.gitconnected.com/building-a-native-editor-for-ios-968ff9bc6e0c">Building a native editor for iOS</a> was originally published in <a href="https://levelup.gitconnected.com">Level Up Coding</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Lists in UITextView]]></title>
            <link>https://blog.devgenius.io/lists-in-uitextview-756fe2b1407a?source=rss-cee883b2eeac------2</link>
            <guid isPermaLink="false">https://medium.com/p/756fe2b1407a</guid>
            <category><![CDATA[rich-text-editor]]></category>
            <category><![CDATA[lists]]></category>
            <category><![CDATA[uitextview]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Rajdeep Kwatra]]></dc:creator>
            <pubDate>Fri, 03 Jul 2020 01:44:43 GMT</pubDate>
            <atom:updated>2020-07-07T10:56:11.459Z</atom:updated>
            <content:encoded><![CDATA[<p>Have you ever wished that you could achieve something like the following in a UITextView:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FV-UiuimLNgWqJzJ-SALOQ.gif" /></figure><p>It is really odd that something that is used so widely, is not supported natively by UITextView on iOS. When I came across a scenario (more on that later — be sure to read till the end 🙂) where I needed to implement a functional list in UITextView, it seemed that I had hit a roadblock. Right at the onset, I knew that the only option I have is to use custom attributes in NSAttributeString. However, as it turned out, I had to try more than a few approaches to finally be able to create an implementation that I was looking for.</p><h3>First attempt</h3><p>The first approach that I attempted was as follows:</p><ol><li>Create a custom NSAttributedString attribute with name listItem.</li><li>Whenever a range is selected for applying list formatting, get all the lines separated by new line character, and add additional text before each line with bullet symbols. Also, update paragraphStyle attribute to add indents.</li></ol><p>This approach had quite a few issues:</p><ol><li>When the text was added (denoting bullet/number), the overall range of text changed making it difficult to loop through lines that were in the range originally selected by the user.</li><li>Keeping a track of index denoting the bullet/number was tricky especially when items got deleted/added in the middle.</li><li>Paragraph indentation needs to account for bullets/number widths, which in-turn needed to be right aligned.</li><li>It gets really tricky to control the indentation beyond first level of list items.</li></ol><p>While this approach can work relatively well in case you are trying to show lists in a UILabel (where content does not change), it is far from perfect to use the same for UITextView where a user may change text and lists need to adjust dynamically.</p><h3>NSLayoutManager to the rescue</h3><p>The biggest learning from the first attempt was that I cannot use an approach that involves changing the text, programatically, to include markers for lists i.e. bullets/numbers etc. Giving it some more thought and traversing the documentation of key parts of TextKit, I figured out that customizing NSLayoutManager is probably the best bet to make it work.</p><p>At a very high level, the approach that worked is:</p><ol><li>Subclass NSLayoutManager to override <a href="https://developer.apple.com/documentation/uikit/nslayoutmanager/1403158-drawglyphs">drawGlyphs</a> function.</li><li>Loop over the content to find presence of a custom attribute .listItem in layoutManager.textStorage which can be applied by user by selecting a range of text.</li><li>Using enumerateLineFragments , loop over the line fragments in the layoutManager. It is important to note that a line fragment is actual laid out line in UITextView and not the line separated by new line character. Purpose of using this function is so that we get rect for each of the line, and use that to position custom drawing of glyphs (bullets/numbers) at the given location.</li><li>For each of the content range identified as a paragraph (i.e. separated by new line character), create a copy of NSParagraphStyle and update firstLineHeadIndent and headIndent.</li><li>Re-apply the updated paragraphStyle from above to the same range. A copy is required as if you change the existing attribute, it will apply to the entire range of that style which may be beyond a single line (ending in newline character) of text.</li><li>Using the line fragment rect that we got from enumerateLineFragments , calculate positions to draw custom image/text denoting the list markers i.e. bullet/numbers.</li></ol><p>The benefit of using this approach is that since layoutManager is triggered on every key press effectively, it is easier to maintain the indexes for numbering the list items. i.e. when items get added/deleted in the middle of a list, it is automatically reindexed based on the layout.</p><p>However, this approach only takes care of list items in a selected range of text. When working with lists, users expects more than that. A text view should support the following:</p><ol><li>Select range of text and apply list styling. This should automatically create as many list items as there are number of lines in the selected range.</li><li>When user presses enter key, it should create a new list item at the same level where user is at.</li><li>User should also be able to use tab/shift-tab (macOS Catalyst) to indent/outdent list item(s).</li><li>Hitting enter twice at the last list item should exit the list.</li></ol><p>The aforementioned behaviour can be obtained by using UITextViewDelegate functions to intercept key presses and update the listItem attribute at given range. For intercepting shift-Tab, a UIKeyCommand may be used. This can then again be read by LayoutManager in overridden drawGlyphs and laid out as expected.</p><h3>An easy way out</h3><p>As mentioned in the beginning, I needed to create lists — and this requirement was for an open source project — <a href="https://github.com/rajdeep/proton/">Proton</a>. Proton is a project that I work on in my spare time. The motivation for developing <a href="https://github.com/rajdeep/proton/">Proton</a> came from the fact that while UITextView is very powerful, it only exposes very little of that power out of the box. You really need to put quite a lot of pieces (TextKit) together to come up with a native iOS/macOS Catalyst text editor that is capable of supporting different kinds of text formatting. <a href="https://github.com/rajdeep/proton/">Proton</a> helps make that part easier.</p><figure><img alt="Proton" src="https://cdn-images-1.medium.com/max/1024/1*47_BkChF6mpSnqOSBGaRQQ.png" /></figure><p>What you see above in an example from <a href="https://github.com/rajdeep/proton/">Proton</a> which encapsulates TextKit components to provide rich text editing capabilities. Proton is able to achieve lists using the following:</p><ol><li>EditorView: The editable text view that internally uses a UITextView with custom NSTextStorage and NSLayoutManager .</li><li>ListCommand : Proton has a concept of commands that can be invoked on an EditorView. Commands can be internally created and registered with EditorView.</li><li>ListTextProcessor: A text processor is a piece of code that is executed as user changes the text. With this, it is easier to intercept special key inputs like Enter, Tab etc. along with key modifiers like Ctrl, Alt, Shift. Like commands, these only needs to be registered.</li><li>EditorListFormattingProvider: A protocol that you need to implement and set on editorView.listFormattingProvider. This is used to query the number/bullet that for each of the index. You can return a text value or even an image to be used as the list marker.</li></ol><h4>Code with Proton</h4><p>When using <a href="https://github.com/rajdeep/proton/">Proton</a> EditorView, you only need to add the following to get lists functionality:</p><pre>let command = ListCommand()<br>let attributeValue: Any? = &quot;anyValue&quot;<br>command.execute(on: editor, attributeValue: attributeValue)</pre><p>attributeValue can be any value that you can add to list items. This value is returned back along with the index of item to EditorListFormattingProvider and can be used to keep context like if the list is bullet or a numbered list.</p><p>To get functionality that handles (Shift) Enter, (Shift) Tab and backspace, all you need is:</p><pre>editor.registerProcessor(ListTextProcessor())</pre><p>ListTextProcessor takes care of all the formatting as user types text in a list including creating new items, indenting and outdenting lists as well as exiting lists.</p><p>A few more examples of lists in Proton running on macOS Catalyst app:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rWu1DU50-DvRgmqvSPKulA.gif" /><figcaption>Creating list from text as it is typed</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*PdOnsnq5Bb-RT2eLNibQFQ.gif" /><figcaption>Creating list from existing text</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dQUqIMmi7r3wdhOymgGj0A.gif" /><figcaption>Indent/Outdent using Tab/Shift-Tab</figcaption></figure><p>Thank you for your time to read this article. This is the first of a series of articles that I plan to write about <a href="https://github.com/rajdeep/proton/">Proton</a>, the approaches that worked and ones that didn’t and my learnings. I look forward to seeing you in the next article.</p><p>Until then, take care and stay safe! 🙂</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=756fe2b1407a" width="1" height="1" alt=""><hr><p><a href="https://blog.devgenius.io/lists-in-uitextview-756fe2b1407a">Lists in UITextView</a> was originally published in <a href="https://blog.devgenius.io">Dev Genius</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Multiple shadows on UIView]]></title>
            <link>https://medium.com/@rkwatra/multiple-shadows-on-uiview-7ef567d7acae?source=rss-cee883b2eeac------2</link>
            <guid isPermaLink="false">https://medium.com/p/7ef567d7acae</guid>
            <category><![CDATA[uiview]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <dc:creator><![CDATA[Rajdeep Kwatra]]></dc:creator>
            <pubDate>Wed, 20 Mar 2019 05:59:03 GMT</pubDate>
            <atom:updated>2019-03-20T05:59:03.370Z</atom:updated>
            <content:encoded><![CDATA[<p>Recently, I came across a requirement of having multiple shadows on a single UIView. The requirement was pretty straightforward:</p><ul><li>Have a perimeter shadow with1px width.</li><li>Have an ambient shadow which will be variable to give an impression of elevation, as in <a href="https://material.io/design/environment/elevation.html#elevation-in-material-design">Material</a> design.</li></ul><p>The expected result was as follows:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*FBDVJwStsNzfV-RWkdpfrA.png" /></figure><p>I wanted to make this elevationgeneric such that it can be applied to any view. My experience on this piece of code turned out to be rather eventful unlike what I was expecting. In this article, I am going to talk about the evolution of the code that I used for getting what our designer was looking for.</p><p>At first glance, it seemed like I can just use layer.border for the perimeter shadow, however it did not yield the result as what was expected. Using layer.borderseems much darker and has no spread like what you get if you use a shadow instead:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/543/1*lORsXWNy6QmAray5EGUdVg.png" /></figure><p>To keep the approach generic, I created an extension called applyShadowsover UIView and added the code as shown in snippets below.</p><h3>1st attempt — Using BezierPaths</h3><p>The first attempt was to use UIBezierPath on the layer of view:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/23d4cab12090b213b645c2677e31f9c6/href">https://medium.com/media/23d4cab12090b213b645c2677e31f9c6/href</a></iframe><p>And similarly, ambientShadow can also be created with the only difference being in shadowRadius and shadowOffset to give an impression of elevation. The following code then adds the shadow layers to the view’s layer:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/68269f582f8fcb8ef1a92d72c5eb6328/href">https://medium.com/media/68269f582f8fcb8ef1a92d72c5eb6328/href</a></iframe><p>While this worked, it seemed that using sublayers would simplify the code a little.</p><h3>2nd attempt — Using Sublayers</h3><p>When using a sublayer we can avoid the additional code required to define the shadowPath:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5d899379e6ddcb0d36e4ee90567a91be/href">https://medium.com/media/5d899379e6ddcb0d36e4ee90567a91be/href</a></iframe><p>This code looks much cleaner and straightforward than using UIBezierPath and result is exactly the same output.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/460/1*suUgKPHQwu7kES3vKj7YiQ.png" /></figure><p>It all seemed to be working fine until I tried it on the view the elevation was expected to be applied. As shown in the graphic below, the elevation code did not account for rounding of subviews of the view on which elevation was being applied. This resulted in a broken UI:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/644/1*ZXkQqmdAeYILF8SYwGUK3Q.png" /></figure><p>As visible in the graphic above, while the parent view has rounded corners and shadows, the subview is not rounded.</p><h3>3rd attempt — Insets on shadow layer</h3><p>To fix the issue of rounding, I could not have used clipsToBound as it would result in shadows being clipped as well. As a workaround, I thought of using edge insets equal to the cornerRadius.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/18bed81ab02c192024807b7566319f8f/href">https://medium.com/media/18bed81ab02c192024807b7566319f8f/href</a></iframe><p>Using insets for the frame of the shadow seemed to fix the issue:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/598/1*Kp3Wy2CCHiJKqQscnfXeSg.png" /></figure><p>However, this approach can be used in some specific cases only. For e.g. this approach will not work if the subview is scrollable and is expected to be touching the parent view bounds while scrolling. Following graphic shows the issue visually:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/460/1*e4WwLnuw5WVPorZeXolkFQ.png" /></figure><p>In the graphic above, the yellow color is of the parent view and cyan is the subview. This approach was more of a hack than a solution. This hides the issue rather than fixing it.</p><h3>4th attempt — Masking subviews</h3><p>UIView provides a property called mask which seemed to be the solution to the problem I encountered in the 3rd attempt. Using a mask , we can round the subview without having the hack of insets on shadows:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/671cc39e5f2ea155cab54f4c8eeeda19/href">https://medium.com/media/671cc39e5f2ea155cab54f4c8eeeda19/href</a></iframe><p>With the masks applied, we get the expected result:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/446/1*g1jgbv8VW1QLw2WHCrB5zg.png" /></figure><p>With this attempt, we solved the problem of non-rounding of subviews and we do not have any additional insets either. While it seems that this approach work, this again poses issues with scrollable subviews:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*HINZmdB5xnzsMwGtsw3IZw.gif" /></figure><p>In the gif above, the blue color is of the parent view which contains a scrollable child view. The child view has 9 items but we see only 4 as others are hidden by the mask we applied.</p><h3>5th attempt — Using additional view for shadows</h3><p>So the solution to the problem that I kept running into again and again was clear — I’ll have to use clipToBounds on the view to get desired rounding at the corners. This also meant that I can no longer have shadows applied on the view in question. However, I can still achieve the desired appearance using the following approach:</p><ul><li>Create an additional view with same frame as the current.</li><li>Add shadows using sublayers approach to the new view.</li><li>Position the new view behind the current view.</li><li>Set clipsToBounds on the current view.</li></ul><p>and that’s it.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1eb903cfe4359d4cb31d9aea47359a2b/href">https://medium.com/media/1eb903cfe4359d4cb31d9aea47359a2b/href</a></iframe><p>I then updated the code to add shadows to the shadowView:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/93270d5bd51812f7afd3f1bd544629cf/href">https://medium.com/media/93270d5bd51812f7afd3f1bd544629cf/href</a></iframe><p>With this change in place, we are able to get shadows applied to a view with rounded corners and a scrollable subview:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/480/1*XQsgKlJ4wCio7pNikD-0aQ.gif" /></figure><h3>Bonus tips</h3><ul><li>Layer names: you must have noticed that I have set layer.name to a value perimeterShadow. This serves as an identifier to remove/resize layers where I can just query all the sublayers to get the shadow layers.</li><li>Background color for layers: If you don’t set the layer.backgroundColor, the shadows will not show up.</li><li>Layer animation: You can query layer’s animation for key, position to get the duration and timingFunction of the view. This can then be used to resize the shadows with the view as the view size changes as a result of change in orientation.</li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=7ef567d7acae" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>