Devs vs. Designers: What You Need to Know. Episode #1.

Cuberto
5 min readJul 3, 2018

--

We’re initiating a series of posts about the challenges facing Cuberto’s world-class devs where Design with a capital ‘D’ takes precedence. We’ll share non-template app development experiences and give you a glimpse into how our exceptional developers transform novel ideas into solid reality. Disclaimer: our solutions aren’t intended to be a guide or reference to mobile app development.

At the outset it’s worth mentioning that logic-minded devs have a hard time understanding how it’s even possible to sketch an adaptive design without linking every little thing on the smartphone screen to screen resolution. On the other hand, aesthetically-motivated designers don’t see what’s so hard about putting a button and block of text on a single line in both in iPhone 8 and the same in iPhone SE, but along with the input button. This is just a small example of typical designer/developer clashes, but our company always finds a compromise that leaves everybody happy. The takeaway: design and development is a single whole. You shouldn’t order design from a studio that has no development experience. Otherwise, it will be drawing mock-ups without development logic.

After years of working with a variety of applications we’ve hammered out some guiding principles. For example, we don’t waste time on universal components which can be used in other, future projects. Our design philosophy demands a unique approach to each project — we don’t do cookie-cutter templates. We also devote a ton of attention to UI details and make every effort to generate an elegant, supported code while still allowing for a few “workarounds” here and there for achieving the desired effect.

So let’s take a look at this example:

What we see:

  • UIView with the section name shoots up and transforms into the title on the new UIViewController.
  • Meanwhile, the UIView changes slightly (background and font color).
  • UIViews with the remaining sections fly downward behind the selected UIView.

What else we took account of during development:

  • The scroll can be in any position.
  • There can be any amount of sections. In this example, we’re only focusing on three.
  • The animation has to work beautifully on all Apple devices, not just iPhone 8.

This looks like UITableView with a header (title, profile button), UITableViewCells (sections) and a footer. Of course, it’s possible to use UICollectionView with all its magic, but in this case it would’ve just been an unnecessary complication.

Why it’s a good idea to use the UITableView out-of-the-box:

  • Scroll (yes, it’s obvious).
  • Unlimited number of cells.
  • Pull-to-refresh.
  • We can put the same UIView inside the cell, as it was in the header on the second screen.

It’s possible to use cells instead of headers and footers, but we knew in advance that they’d only be used once, so making multiple cell types made little sense.

We put together a work itinerary and here’s what we had to do:

1. Changing the selected cell’s appearance (dark to light).

2. Changing the selected cell’s position (transforming it into a title).

3. Changing the position of the remaining cells (shifting the cells downward).

Our step-by-step solution:

1. Animating the cell’s appearance is possible in the actual UIView with a simple UIView.transition.

2. We have to move the cell into the title position, and then change its UIView into a title. Instead of moving the cell itself into the new controller title, we shifted the title downward, and then simply put it into place. To transition between controllers we used UIViewControllerAnimatedTransitioning.

3. The previous step frees us from fussing about which cell is located in front and which in back, since we can just shift all of them down. But we knew that moving the cells within the actual table can be tricky since it automatically starts applying various insets and contentSize. So we had to implement a bit of workaround wizardry in the code. If you set clipToBounds to false, then you can move the cell’s internal UIView beyond the cell boundaries, creating the effect of moving the cells themselves.

Now let’s check out how this looks in the code itself.

Changing a selected cell’s appearance:

//Public UIView method, which is into the cell.
func setStyle(_style: Style) {
self.style = style

switch style {
case .lightContent:
lblTitle.fontColor = .white
view.backgroundColor = .black
case .darkContent:
lblTitle.fontColor = .black
view.backgroundColor = .white
}
}

Instead of changing property style we’re using the setStyle function. As experience shows, these methods have to be updated during the development process, so it’s easier to take that into account and write a function rather than using the native setter.

Changing a selected cell’s position:

/*
This code is in the target UIViewController.

First, we changed the target UIViewController’s background color to transparent, to make the initial controller visible beneath it.

Then we shift the UIView with the target controller’s title into the initial controller’s selected cell position. We put the cell link into the target UIViewController with a tap.

In the end, along with the animation, we revert the UIViewController’s background color and title position into the initial state.
*/

view.backgroundColor = .clear

let frame = view.convert(categoryView.frame, from: categoryView.superview) listCategoryView.transform = CGAffineTransform(translationX: 0, y: frame.minY — listCategoryView.frame.minY)


UIView.animate(withDuration: itemDuration, delay: 0, options: [.curveEaseOut], animations: {
self.view.backgroundColor = .appBgColor
self.listCategoryView.transform = .identity

})

Changing the cells’ location:

let cells = cellsForAnimation.filter{ !$0.isSelected }tappedListCategoryView?.alpha = 0let itemDelay = duration / TimeInterval(3 * max(1, cells.count)
)
let itemDuration = duration - itemDelay * TimeInterval(max(1, cells.count)
- 1)
for (index, cell) in cells.reversed().enumerated() {
UIView.animate(withDuration: itemDuration, delay:
TimeInterval(index) * itemDelay, options:[.curveEaseOut],
animations: {
cell.contentView.subviews.first?.transform =
CGAffineTransform(translationX: 0, y:
self.tableView.rowHeight * 1.25)
})
}

We didn’t make a reverse animation for several reasons:

  1. The target UIViewController has a lot of list elements. That means that when returning to the main screen, the user can scroll the header beyond visibility, and it’s unclear how to transform the title into the cell.
  2. Implement a reverse animation into the interactive-pop-gesture would require a long, difficult process. Making a different animation for interactive-pop-gesture and for the Back button isn’t the best idea, anyway.

We unpacked one of the simplest animation examples which Cuberto made happen. Our next post will feature something a bit more elaborate and universal.

Cuberto sets the trend in creative websites and mobile apps. Digital and mobile expertise powers our award-winning designs and innovative high-end products. info@cuberto.com

Follow us on Dribbble and Instagram

--

--

Cuberto

Leading digital agency with solid design and development expertise. We build mobile and web products for startups.