Smart caption by UILabel or UITextView - objective-c

I would like to create a smart caption as SoundCloud app did.
See the attachment below,
These two captions:
- •PAN•
- Berlin, Germany
are what I want create.
These captions seem to be executed by sizeToFit or sizeThatFits. However, if using sizeThatFits with background colour (by NSBackgroundColorAttributeName), you won't get padding both before the first and after the last letters and top and bottom paddings as well.
The caption will be organised the exact fit size as these letters.
Anyway, what I would like to do is the exact same caption like the attachment picture.
Cheers,

You have two approaches here. One is to add a bit of padding after calling sizeThatFits. The other is to prepend and append a space to your label title.
The right way about adding the padding, though, would be to extend UILabel and on your subclass, override the method textRectForBounds:limitedToNumberOfLines:. In there, just call the same method on super passing the bounds you receive, only smaller.

I know is an old question but i was looking for the same effect that SoundCloud has on its labels.
here is the subclassing of uilabel
import UIKit
class LabelPine: UILabel {
override func drawTextInRect(rect: CGRect) {
let insets = UIEdgeInsets.init(top: 5, left: 0, bottom: 5, right: 3)
super.drawTextInRect(UIEdgeInsetsInsetRect(rect, insets))
}
override func textRectForBounds(bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
super.textRectForBounds(bounds, limitedToNumberOfLines: 0)
return CGRectInset(self.attributedText!.boundingRectWithSize(CGSizeMake(999, 999), options: .UsesLineFragmentOrigin, context: nil), -5, -5)
}
}
And here is the implementation on the respective class:
labelNombre = LabelPine()
labelNombre?.text = nombreUser
labelNombre?.frame = CGRectMake(10, nombrePos.Yo, nombrePos.ancho, nombrePos.alto)
labelNombre?.font = UIFont(name:"Hiragino Sans W3",size: 19)!
labelNombre?.textAlignment = .Left
labelNombre?.backgroundColor = UIColor(white: 1, alpha: 0.5)
labelNombre?.textColor = colorBlentUIColor
labelNombre?.sizeToFit()
header?.addSubview(labelNombre!)
Take notice i call sizeToFit().

Related

Adding margins to TextEditor

I'm adding margins to the TextEditor. While keeping these margins as clickable area.
I was able to add textContainerInset and problem is that added Inset is not clickable.
Current code:
extension NSTextView {
open override var frame: CGRect {
didSet {
textContainerInset = CGSize(width: 72, height: 72)
}
}
}
Current Preview:
Intended behavior (Pages):
Would be grateful for an advice. Thank you very much!
so I found a simple solution and hard one.
1. Simple one
import SwiftUI
extension NSTextView {
open override var frame: CGRect {
didSet {
// Top inset
textContainerInset = NSSize(width: 0, height: 72)
// Left fragment padding <<< This is what I was looking for
textContainer?.lineFragmentPadding = 72
}
}
}
struct TextEditingView: View {
#State private var fullText: String = "One \nTwo \nThree"
var body: some View {
TextEditor(text: $fullText)
.frame(width: 720, height: 480)
.font(.system(size: 24, design: .monospaced))
}
}
As result you get this:
A repository of the demo:
https://github.com/yaosamo/Swift-TextView-Demo
2. Second solution
Using NSParagraphStyle, headIndent, firstLineHeadIndent
I believe this is how indents on Pages on Mac implemented. I do not know tho how they persist default indent. If you open ruler you will see that it set to 1 and you can't go below it.
Using code of
(AppKit) Tab insertion inside of NSTextBlock
class ParagraphStyle {
let bgColor: NSColor
let paragraphStyle: NSParagraphStyle
init(bgColor: NSColor) {
self.bgColor = bgColor
//Set paragraph style
self.paragraphStyle = {
let mutableParagraphStyle = NSMutableParagraphStyle()
let specialBlock = CustomTextBlock(bgColor: bgColor)
mutableParagraphStyle.textBlocks.append(specialBlock)
mutableParagraphStyle.headIndent = 50 // Add indent here
let style = mutableParagraphStyle as NSParagraphStyle
return style
}()
}}
you can add headIndent to text style. And it will work for copy that you insert there. Problem like I said if you start typing Indents break and I don't know how to preserve it.
First one works for me exactly how I want it. Next will figure out how to use headIndent/FirstlineheadIndent
Thanks to this community I was able to find a solution! Don't give up you also can make it! :D

How to create the equivalent of a SwiftUI stack view spacer programmatically

I'm working on trying to recreate the first SwiftUI Tutorial in code without using SwiftUI. In the example, it mentions using a Spacer "to direct the layout to use the full width of the device":
VStack {
Text("Turtle Rock")
HStack {
Text("Joshua Tree National Park")
Spacer()
Text("California")
}
}
For the VStack, HStack, and Text views, I can easily use UIStackView and UILabel. But for the Spacer, I can't seem to find any equivalent in the standard library (no UISpacer or anything like that), which makes me think this is something custom to SwiftUI. In the tutorial, it describes how this Spacer works:
A spacer expands to make its containing view use all of the space of its parent view, instead of having its size defined only by its contents.
So how can I recreate the functionality of this Spacer view programmatically? Do I just add a constraint to the UIStackView to make it full width? Or is there a way to add a subview to the UIStackView that makes it behave like it does in SwiftUI?
I have worked solution using dummy UIView() which has set big constant widthConstraint using low priority - this ensures UIView will grow as much as possible but will not grow over superview constraints since it has lower priority.
Example:
let titleLabel = UILabel()
titleLabel.text = "Joshua Tree National Park"
let spacer = UIView()
// maximum width constraint
let spacerWidthConstraint = spacer.widthAnchor.constraint(equalToConstant: .greatestFiniteMagnitude) // or some very high constant
spacerWidthConstraint.priority = .defaultLow // ensures it will not "overgrow"
spacerWidthConstraint.isActive = true
let descriptionLabel = UILabel()
descriptionLabel.text = "California"
UIStackView(arrangedSubviews: [titleLabel, spacer, descriptionLabel])
Swift 5
You can create an extension for UIView to create a spacer in this way:
extension UIView {
static func spacer(size: CGFloat = 10, for layout: NSLayoutConstraint.Axis = .horizontal) -> UIView {
let spacer = UIView()
if layout == .horizontal {
spacer.widthAnchor.constraint(equalToConstant: size).isActive = true
} else {
spacer.heightAnchor.constraint(equalToConstant: size).isActive = true
}
return spacer
}
}
After that, you can add your spacer into stacks in this way:
// ... some code
let stack = UIStackView(arrangedSubviews: [UIView.spacer(), UILabel(), UIView.spacer(), UILabel(), UIView.spacer()])
stack.axis = .horizontal
stack.distribution = .equalSpacing
// For vertical stacks
let stack = UIStackView(arrangedSubviews: [UIView.spacer(for: .vertical), UILabel(), UIView.spacer(for: .vertical), UILabel(), UIView.spacer(for: .vertical)])
stack.axis = .vertical
stack.distribution = .equalSpacing
I think in this way, you can play with spacer size/layout and stack distribution/alignment to get the desired space.
A plain UIView() can replace a SwiftUI.Spacer as long as distribution is set to fill, since it has no set width constraint. I've only tested this vertically. However, you should note the layout performed by UIStackView and SwiftUI.HStack are not actually the same steps, though the end results may appear similar; something to look into.

margin of customMediaItem in jsqmessageviewcontroller

i have a class that extend: JSQLoadingPhotoMediaItem, all works fine expected that in my chat i do not use image for bubble, but i have a background color and radius for textView inside the bubble, if i use the class i obtain this:
The first one is the textView of the cell with a color background, the second one is a view that i return from class with this code:
view = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.mainScreen().bounds.width, height: 38))
view!.backgroundColor = UIColor(red:0.89, green:0.98, blue:0.78, alpha:1)
view!.layer.cornerRadius = CGFloat(9)
view!.layer.masksToBounds = true
in a function
override func mediaView() -> UIView!
How can i give the same right margin to my custom class? or if for example would like to have a view of custom class aligned center?
Thanks!
I also had the same problem. To get the same margin for my bubbles I resorted to using the same JSQMessagesMediaViewBubbleImageMasker from JSQMessagesMediaViewBubbleImageMasker.h in my custom media view
//apply mask to your view
[JSQMessagesMediaViewBubbleImageMasker applyBubbleImageMaskToMediaView:view isOutgoing:self.appliesMediaViewMaskAsOutgoing];
You can create a category of JSQMessagesMediaViewBubbleImageMasker and extend it however you wish, there was a particular case where I needed a specific color for the border of the bubble.
Thanks! i found a solutions, i have a clear background for the main view, and inside another subview with right or left margin based on sender, backgroundColor and corner radius!

placeholder text and typed in text not aligning in UITextField

I have a UITextfield with some placeholder text.
I have used both alignment properties. However, the palceholder text is still a little on the upper side. Can anyone help me out ?
Thanks.
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
Here's my solution in MonoTouch for having to fix the alignment of placeholder vs text. As I noted in the comments -- there are three distinct pieces: the editing, the static text, and the static placeholder. The equivalent in Objective-C is drawTextInRect: and drawPlaceholderInRect:.
My solution was to subclass and offset the mis-aligned items. Unfortunately the issue seems to be related to the font-file itself and how editing mode affects it, vs. how iOS renders static text.
Hope this helps someone.
Allison
public class MyTextField : UITextField
{
public MyTextField(RectangleF rect) : base(rect)
{
}
public override void DrawPlaceholder(RectangleF rect)
{
base.DrawPlaceholder(new RectangleF(rect.X, rect.Y + 2, rect.Width, rect.Height));
}
public override void DrawText(RectangleF rect)
{
base.DrawText(new RectangleF(rect.X, rect.Y + 2, rect.Width, rect.Height));
}
}
According to UITextField documentation you should be using the textAlignment property. As the docs state "This property applies to the both the main text string and the placeholder string. The default value of this property is UITextAlignmentLeft."
So your code would look something like:
textfield.textAlignment = UITextAlignmentLeft
or depending on how you want to align the text you could use UITextAlignmentCenter or UITextAlignmentRight after the = sign.
I'd say play around with the Y Size of you used CGRectMake to create your frame. Maybe make it smaller?

dojox.drawing.Drawing - custom tool to create rectangle with rounded corners

I'm working with dojox.drawing.Drawing to create a simple diagramming tool. I have created a custom tool to draw rounded rectangle by extending dojox.drawing.tools.Rect as shown below -
dojo.provide("dojox.drawing.tools.custom.RoundedRect");
dojo.require("dojox.drawing.tools.Rect");
dojox.drawing.tools.custom.RoundedRect = dojox.drawing.util.oo.declare(
dojox.drawing.tools.Rect,
function(options){
},
{
customType:"roundedrect"
}
);
dojox.drawing.tools.custom.RoundedRect.setup = {
name:"dojox.drawing.tools.custom.RoundedRect",
tooltip:"Rounded Rect",
iconClass:"iconRounded"
};
dojox.drawing.register(dojox.drawing.tools.custom.RoundedRect.setup, "tool");
I was able to add my tool to the toolbar and use it to draw a rectagle on canvas. Now, I would like to customize the rectangle created by my custom tool to have rounded corners, but I'm not able to figure out how.
I have checked the source of dojox.drawing.tools.Rect class as well as it's parent dojox.drawing.stencil.Rect class and I can see the actual rectangle being created in dojox.drawing.stencil.Rect as follows -
_create: function(/*String*/shp, /*StencilData*/d, /*Object*/sty){
// summary:
// Creates a dojox.gfx.shape based on passed arguments.
// Can be called many times by implementation to create
// multiple shapes in one stencil.
//
//console.log("render rect", d)
//console.log("rect sty:", sty)
this.remove(this[shp]);
this[shp] = this.container.createRect(d)
.setStroke(sty)
.setFill(sty.fill);
this._setNodeAtts(this[shp]);
}
In dojox.gfx, rounded corners can be added to a a rectangle by setting r property.
With this context, could anybody please provide answers to my following questions?
What's the mechanism in dojox.drawing to customize the appearance of rectangle to have
rounded corners?
In the code snippet above, StencilData is passed to createRect call. What's the mechanism to customize this data? Can the r property of a rectangle that governs rounded corners be set in this data?
Adding rounded rectangles programmatically is easy. In the tests folder you'll find test_shadows.html which has a line that adds a rectangle with rounded corners:
myDrawing.addStencil("rect", {data:{x:50, y:175, width:100, height:50, r:10}});
You create a data object with x,y,width,height, and a value for r (otherwise it defaults to 0).
If you wanted to do it by extending rect, the easiest way to do it would just be to set the value in the constructor function (data.r=10, for example), or you could create a pointsToData function to override Rect's version. Either you would have set the value for this.data.r, or the default:
pointsToData: function(/*Array*/p){
// summary:
// Converts points to data
p = p || this.points;
var s = p[0];
var e = p[2];
this.data = {
x: s.x,
y: s.y,
width: e.x-s.x,
height: e.y-s.y,
r:this.data.r || 10
};
return this.data;
},
In that example I give r the value 10 as the default, instead of 0 as it was before. This works because every time stencil goes to draw your rect, it converts canvas x,y points (all stencils remember their points) to data (which gfx uses to draw). In other words this function will always be called before rect renders.