Description
Mobile Application Development
Creative Features
For this lab we want you to incorporate two creative features. A combination of many smaller features is feasible but it will make your description of them hard. If you do choose many smaller features try to make sure they can be grouped towards two greater goals. A “creative feature” doesn’t have to be a literal feature, it can involve an abstract concept. Try to defend your creative decision in your head, if you struggle to justify the significance then it’s probably not enough. A laundry list of small features would also be hard to defend. Put yourself in the shoes of an app developer — what is a significant improvement you can make to this app? Start brainstorming early!
Once again, in the body of your email please defend your creative feature, use it as your chance to tell us why it is worth 10 or 20 points.
Example format:
- What you added (and how to use it)
- How you added it and what the process involved
- How does it compare to the effort required by the other portions?
- Why you added it
- Why it is a meaningful improvement to the drawing app?
For reference, creating a white-colored “eraser” color or a re-do button are not significant enough.
Helpful Advice and Code Snippets
The first challenge will most likely be getting data from the user’s input. The way to do this is by overriding the touchesBegan, touchesMoved, and touchesEnded functions in your view controller. After these are in place, use the following code to get the location of a user’s touch.
guard let touchPoint = touches.first?.location(in: view) else { return }
This function takes the first touch from a set of UITouch objects provided by the system, and finds its location in the current view. This limits the user to only inputting a single touch at a time, but it should suffice for the purposes of this lab. When drawing a line, think about what you want to do with this position and how often you want you want that to happen. Collect points from the user’s touches and create a line!
An easy way to implement custom drawing is to override the drawRect function of a custom UIView. Create a new class which subclasses UIView, and override the drawRect function. This is where the custom drawing will take place, and is called automatically. If you need to refresh what is displayed in the view, the setNeedsDisplay function will call drawRect for you. Do not call drawRect directly. This allows the graphics system to optimize how often the screen is redrawn, and it will only execute drawRect if the display needs to be updated for the next frame to be displayed.
As for the lines themselves, I recommend using a UIBezierPath object, which has a lot of convenient methods to incrementally build and store complex paths. It is a higher-level wrapper object for the underlying CGPath object, and integrates with UIKit easily. It is quite straightforward to draw a UIBezierPath in a UIView (search for the UIBezierPath class reference online to find out how). If you are digging into the depths of Core Graphics or Objective-C, you have probably missed an easier solution. You should be avoiding any sort of “addSubview” operation.
The UIBezierPath class also comes in handy for smoothing out your lines (which otherwise may look jagged and unpolished). There are many path smoothing algorithms, but one of the simplest is given below. It uses the original points as control points for the bezier curve, and the midpoints between each pair of points as the actual points. (If you have worked with the pen tool in any vector drawing application the concept of anchor points and control points might be familiar to you.) In any case, below is a function which takes in an array of CGPoints, and returns a smooth UIBezierPath. It requires the use of a midpoint helper function, which I will leave as an exercise for the reader. When drawing a line, quickly change directions and make sure it stays smooth.
private func midpoint(first: CGPoint, second: CGPoint) -> CGPoint {
// implement this function here
}
private func createQuadPath(points: [CGPoint]) -> UIBezierPath { let path = UIBezierPath() //Create the path object if(points.count < 2){ //There are no points to add to this path
return path
}
path.move(to: points[0]) //Start the path on the first point
for i in 1..<points.count – 1{ let firstMidpoint = midpoint(first: path.currentPoint, second:
points[i]) //Get midpoint between the path’s last point and the next one in the array let secondMidpoint = midpoint(first: points[i], second: points[i+1]) //Get midpoint between the next point in the array and the one
after it
path.addCurve(to: secondMidpoint, controlPoint1: firstMidpoint, controlPoint2: points[i]) //This creates a cubic Bezier curve using math!
} return path }
Lastly, this application provides a great opportunity to leverage object-oriented programming principles to make your code easier to read and maintain, as well as save you time. If you are going to make a button for seven different colors, consider creating a UIButton subclass so you only have to write your button styling code once. Or, if you need to store additional information along with a UIBezierPath (like its color or thickness, for example), consider creating your own custom class/struct to keep all that relevant data together.
Think about structuring your app according to the model-view-controller paradigm. What is the model? What is the view? How do we connect those pieces in a reusable way? Which object should be responsible for the createQuadPath function? Contemplating these questions may seem trivial for a simple app, but becomes critical as your codebase scales.
Good luck and have fun!
An example of a working drawing app. Notice that the lines are smooth (not just connected line segments) and the user can tap to draw dots.



