OS X chat app with resizable bubbles - objective-c

I'm building chat application for Mac OS, similar to iMessage. I wonder, how can I implement resizable text views in bubbles. I mean, when I resize chat window bubbles with text will resize to. Any ideas, links will be very useful. Thank you for help)

For text resizing, you use auto layout. If you have an NSScrollView containing MYBubbleViews containing NSTextViews, you can add NSLayoutConstraints using the leftAnchor and rightAnchor properties of the scroll view's content view and those of the bubble view, and add constraints between all edges of the text view and bubble view. Then pin the bubble views to the top/prev view.
Also make sure you set the NSTextView to wrap. The width of the intrinsic size of the text view will be set so that it fills the width and the intrinsic height will be set to fit the whole text.
I previously thought it was about drawing the bubbles, so I first gave this answer:
If you look at Messages.app, you'll see that they're not circular bubbles. They are basically composed of several shapes overlaid on each other. A rectangle with rounded corners, plus a bezier path of the tip.
So you should be able to take a NSTextView for the text, make it a subview of a custom view that draws a rounded rectangle and the tip in its drawRect method, and then use auto layout constraints to make your bubble view resize with the text view and the text view to the window width.
You could probably also have the bubble view host a CALayer with fill and rounded corners, plus one with an image for the tip (or aCAShapeLayer for the tip), but drawRect is the easier approach.

Related

Completely transparent UIButton with irregular hit area

I know how to use a background image with alpha channel to create a UIButton with an irregular tap area. But with this solution, only the ignore-tap area is transparent; the tap area consists of the opaque.
What I want is a totally transparent UIButton, with an irregular tap area. (It triggers an animation behind the button.)
It seems that some sort of extra UILayer with some hit-testing could work, but I don't quite see how. Suggestions welcome.
Here's my solution. The problem: A UIImageView (call it the base view) to which I want to attach an irregularly-shaped tap area. The area corresponds to something in the image, let's call it a river. It could be a non-connected region.
In the Finder, duplicate the view's image, and make all the non-river pixels transparent, using your favorite graphics app. Call this the mask image.
When the base view is tapped, check to see if the corresponding pixel in the mask image is or is not transparent. (Solution left to reader; examples abound.)
So the mask image is never actually rendered, it is just used as a reference.
Note that if the base view gets resized or moved around (as it does in my app, via animating its constraints) then you have to "move" the mask image too, or in some other way manage the coordinate translation between view and mask. The easiest way to do this is to make the mask image a hidden subview of the base view, with its left, top, leading and trailing anchors constrained to be equal to those of the base view. Then they move around together, and the coord translation between the two is the identity.
I wrapped all this up in a subclass of UIImageView so that it manages its own mask, and calls a delegate if the "river" (or whatever) is tapped.

Auto-resizing NSScrollView that wraps an NSTextView

How do I tell an NSScrollView that wraps an NSTextView to grow with the NSTextView until a maximum?
== In more details:
The UI is common in many messanger/chat app. Initially, the NSTextView is empty and has just enough height to show one line of text. The NSScrollView is just enough to fit the NSTextView. As the user type in more text, the NSScrollView should grow along with the NSTextView, until reaching a maximum height, then start showing the vertical scroll bar.
Observe NSTextStorageDidProcessEditingNotification on the text storage of the text view. Then call usedRectForTextContainer on the layout manager to determine how large the text is for the view's text container.
You may also need to add extraLineFragmentRect to it, I'm not sure. That's also available from the layout manager.

iOS: Drawing a Rectangle on an ImageView and Adjusting Borders

Attached 1 is a screenshot from an app called GeniusScan where you can photograph any document and an adjustable rectangular grid shows on the imageview. You can easily adjust the borders of the grid with your fingers to select the portion of the image that you want to scan. It will be then transformed into the correct prospective.
1- How can I draw and interact with the grid on the imageview?
2- How can I return the corner points of the grid to my view controller.
Update: I found a wonderful class called BJImageCropper which allows to use fingers to ajust the borders, but only for a box like rectangle. Can anyone suggest how it can be updated to support shapes like in the GeniusScan app?
Dude:
I created a demo that solves both questions:
1- How can I draw and interact with the grid on the imageview?
By Adding 4 views that will act as interactive control points by adding UIPanGestureRecognizer and then drawing the grid using CAShapeLayer on top of your view.
2- How can I return the corner points of the grid to my view controller.
You must keep references to the four control points of your grid.
Here's the link to my code.
This isn't actually drawing on top of UIImageView. It's actually an overlay (view) on top of the UIImageView. You need to keep track of 4 points (have 4 views as subview of the layer), track their positions, once moved, use drawRect: to draw lines based on the 4 points.
The way I've implemented it in my app is, I overlay the UIImageView with a transparent 'SelectionView' (a custom view that I wrote). The selectionView contains 4 custom subview of class 'Vertex'. The vertex talk back to the selectionView via protocol method every time user touches/moves it (it's actually not important which vertex moved, just that it moved):
- (void)vertexMoved:(Vertex *)vertex;
Then the selectionView knows that it needs to re-draw, so it calls setNeedsDisplay which calls internally calls drawRect (you should never call drawRect) where I do the actual drawing of the bounding rect. Basically, iterate through each vertex and draw a line using Quartz APIs and fill it with semi transparent/hollow color.
This is how I am doing it atleast, I am sure there are other ways.

Resizing CAShapeLayer

I have a simple test app on which my rootViewController's UIView contains a bunch of UIView subviews. Each one of those UIView subview is backed by a CAShapeLayer.
I want the composition created by those subviews ( the four shapes that are within the dotted area .. ) to always stay vertically and horizontally centered with respect to my
UIWindow. (the minimium size of the left/right, top/bottom margins will be subject to be changed at runtime at each orientation change )
So for example when i rotate to portrait i will have to
resize and reposition those single shapes so that the whole figure will be mantained centered and each CAShapeLayer sublayer stays sharp ( i want their path to be resized not just a raster resize )
what would be the best technique to resize/move the shapes to always have a centered composition while maintaining path crisp appearance for the shapes?
Ultimately for me it will be good to have an answer to this: how can i shrink the subviews as a whole? i mean their sizes and relative positions?
Thanks
You can use CGPathCreateMutableCopyByTransformingPath() or -[UIBezierPath applyTransform:] to recalculate all points in the path.

Rounded corners on NSTableView

I have a custom view subclass similar to NSBox that draws a rounded box background. The problem is that if I place a view like an NSTableView in the box view, it does not clip to the rounded corners. Is there any way to round the corners of NSTableView and its parent scroll view?
I haven't tried this with a table view but have with other controls.
In a subclass of NSTableView (or whatever view/control you want to clip)
Override drawRect:
Create an NSBezierPath with the shape you want (probably appendBezierPathWithRoundedRect:xRadius:yRadius: just remember to use the view's bounds as the size)
Send the path the addClip message to add that shape to the view's clipping path
Call super's drawRect:
If the table view has a header you may need to clip the top corners by subclassing NSTableHeaderView. And if you have scrollbars you may have to do the same thing to them except only clip certain corners. Hopefully you don't have scrollbars because I doubt that would look right. Basically you want to clip the view/control that draws that part, clipping the parent will not cause subviews to be clipped.
If you look at Apple's Welcome to Xcode window they get away with it by drawing a custom header at the top and a text block at the bottom so they don't have to round the table view itself. If you can do something like that I would.