I'm new to this, and new to coding.
I'm working on a quiz app, and here is one of the lines of code:
[questions addObject:#"When was the Declaration of Independence signed?"];
[answer addObject:#"1776"];
But when I test it, the question is too long, so it makes the text extra small, how can I make it so half of it will drop down to the next line?
There are a couple options.
The most basic is to "hard-code" the line break, which is NOT the best option, but I'll spell it out so that you are aware of the difference: this involves splitting the question into two lines by adding a "newline" code (\n) at the point in the question where you want the newline to start. For example:
[questions addObject:#"When was the Declaration\nof Independence signed?"];
This isn't flexible or adaptive, and whether you are using the Interface Builder to configure the object displaying the text (UILabel or UITextView, or other class), the second line of the text may disappear because it falls below the visible area set-up when you create the UILabel or UITextView. This method also goes against best practices because it confounds display with data. There is nothing wrong with your data as it stands.
The better option is to work ONLY with the object displaying the text - which you'd need to do anyway. I'll use UILabel as an example here, but both UILabel and UITextView objects have properties you can set programmatically or in Interface Builder that will effectively enable them not only to stretch their display area instead of shrinking your text, but also to wrap your text at the most logical point based on the new size of the display area.
Programmatically, first make sure that the number of lines for your UILabel object is set to 0:
textLabel.numberOfLines = 0;
You can also do this in Interface Builder if that's where you've created your UILabel.
If that doesn't work, something else is probably not set-up properly - check on the UILabel's metrics to make sure you haven't "locked" its size in any way (its ability to auto-grow or auto-shrink based on the size of its contents).
Related
I'm trying to implement a syntax-coloring text editor that also does things like insert whitespace at the start of a new line for you, or replace text with text attachments.
After perusing the docs again after a previous implementation had issues with undoing, it seems like the recommended bottleneck for this is NSTextStorageDelegate's textStorage(_,willProcessEditing:,range:,changeInLength:) method (which states that Delegates can change the characters or attributes., whereas didProcessEditing says I can only change attributes). This works fine, except that whenever I actually change attributes or text, the text insertion mark moves to the end of whatever range of text I modify (so if I change the style of the entire line, the cursor goes at the end of the line).
Does anybody know what additional call(s) I am missing that tell NSTextStorage/NSTextView not to screw up the insertion mark? Also, once I insert text, I might have to tell it to move the insertion mark to account for text I've inserted.
Note: I've seen Modifying NSTextStorage causes insertion point to move to the end of the line, but that assumes I'm subclassing NSTextStorage, so I can't use the solution there (and would rather not subclass NSTextStorage, as it's a semi-abstract subclass and I'd lose certain behaviours of Apple's class if I subclassed it).
I found out the source of the problem.
And the only solution that will work robustly based on reasons inherent to the Cocoa framework instead of mere work-arounds. (Note there's probably at least one other, metastable approach based on a ton of quick-fixes that produces a similar result, but as metastable alternatives go, that'll be very fragile and require a ton of effort to maintain.)
TL;DR Problem: NSTextStorage collects edited calls and combines the ranges, starting with the user-edited change (e.g. the insertion), then adding all ranges from addAttributes(_:range:) calls during highlighting.
TL;DR Solution: Perform highlighting from textDidChange(_:) exclusively.
Details
This only applies to a single processEditing() run, both in NSTextStorage subclasses and in NSTextStorageDelegate callbacks.
The only safe way to perform highlighting I found is to hook into NSText.didChangeNotification or implement NSTextDelegate.textDidChange(_:).
As per #Willeke's comments to the OP's question, this is the best place to perform changes after the layout pass. But as opposed to the comment thread, setting back NSText.selectedRange does not suffice. You won't notice the problem of post-fixing the selection after the caret has moved away until
you highlight whole blocks of text,
spanning multiple lines, and
exceeding the visible (NSClipView) boundaries of the scroll view.
In this rare case, most keystrokes will make the scroll view jiggle or bounce around. But there's no additional quick-fix against this. I tried. Neither preventing sending the scroll commands from private API in NSLayoutManager nor avoiding scrolling by overriding all methods with "scroll" in them from a NSTextView subclass works well. You can stop scrolling to the insertion point altogether, sure, but no such luck getting a solid algorithm out that does not scroll only when you perform highlighting.
The didChangeNotification approach does work reliably in all situations I and my app's testers were able to come up with (including a crash situation as weird as scrolling the text and then, during the animation, replacing the string with something shorter -- yeah, try to figure that kind of stuff out from crash logs that report invalid glyph generation ...).
This approach works because it does 2 glyph generation passes:
One pass for the edited range, in the case of typing for every key stroke with a NSRange of length 1, sending the edited notification with both [.editedCharacters, .editedAttributes], the former being responsible for moving the caret;
another pass for whatever range is affected by syntax highlighting, sending the edited notification with [.editedAttributes] only, thus not affecting the caret's position at all.
Even more details
In case you want to know more about the source of the problem, I put more my research, different approaches, and details of the solution in a much longer blog post for reference. This here, though, is the solution itself. http://christiantietze.de/posts/2017/11/syntax-highlight-nstextstorage-insertion-point-change/
The above accepted answer with the notification center worked for me, but I had to include one more thing when editing text. (Which may be different from selection).
The editedRange of the NSTextStorage was whack after the notification center callback. So I keep track of the last known value myself by overriding the processEditing function and using that value later when I get the callback.
override func processEditing() {
// Hack.. the editedRange property when reading from the notification center callback is weird
lastEditedRange = editedRange
super.processEditing()
}
In a Xamarin Forms project (C# code, not XAML), I have a some nested horizontal stacklayouts that look like this:
Notice there's a "Declined:" Label, then a quantity Label (4), and then a reason code Label ("Can't Find"). I have set the reason code Label to a LineBreakMode of LineBreakMode.TailTruncation. I would expect that when the label gets too long to fit on the line, it would truncate it with ellipses. It does. However, it doesn't do it gracefully - it causes things to be squished and to word wrap, like this:
I have set the "Declined:" Label to LineBreakMode.NoWrap, and you'll notice the last "d" in "Declined" is cut off". I haven't set any LineBreakMode on the "Ordered" and "Picked" Labels, and you'll notice those word wrap. Why is this happening, and how can I fix it?
Does it look normal again when you rotate the device or if you call ForceLayout() on the parent element to all of those nested StackLayouts?
I have noticed that sometimes I must do that to force a redraw or layout pass on certain devices (usually is it only needed on one platforms or another as opposed to all platforms).
If that doesn't work, I would suggest using Grid if that is possible in your situation. That is what I tend to do when I run into elements sitting on top of each other like this. I am not sure why it happens but Grid never fails me. Grid seems to be much more strict about spacing and does not let things bleed over like that
I am writing a Mac application that provides a "test" like function. This application (through a connection with a server). Basically the application will give the students a story to read, followed by a series of questions (also from the server) where the user can (attempt) to select the correct answers, and send the result back to the server to be verified.
Implementing the "story" part was easy. Just send all of the text to a NSTextView. I had been planning to implement the "select your answer" as programmatically created NSSwitchButtons. However, some of the possible answers might take up more than one line. I have not been able get (any) NSButton class to wrap text based on the frame size, and there doesn't seem to be an easy way to override NSButtonCell to allow the text to wrap.
What other Cocoa class(es) should I use to accomplish this task? I need to have a check-box interface (so that people can select one or more possible answers, and the answers can be an arbitrary length - within reason!) Ideally it would also be easy to use so that it will be easy to programatically layout the answers as well. (Some problems may only have 2 choices, while others may have 5+) I can't imagine I'm the only one who needs this type of functionality
(Oh...since a picture is worth 1,000 words, I've attached a screen-shot of my app below with some answer text running off of the screen)
An NSButton will respect explicit linefeed characters embedded in the text, but I suppose that would not meet your needs. An alternative would be to have a static text item next to a checkbox with no title. Of course, if you want to be able to toggle the checkbox by clicking the text, you would have a little more programming to do.
I have created a "notes" field designed to hold multiple paragraphs of text which I would like to store in a custom object. Originally, I just used an NSTextField as a temporary solution, but this does not allow me to scroll or have multiple paragraphs of text...
In IB I have placed a NSTextView (which seems to be wrapped inside an NSScrollView.) Upon execution of my program, seems to allow me to enter text in multiple paragraphs, scroll, etc. In short it LOOKS to be exactly what I want would like it to be. So far so good.
Now, I need to retrieve the data from this field and store it in my custom object. This is where I'm getting a bit lost within the developer documentation...
My goals are fairly straight forward:
Allow users to type away in the box.
Store the contents of the box into a variable (array, etc.) in my custom object when the user moves to another field, leaving the notes field.
Display the users stored text in the text box next time the record is viewed.
Second, is there a simple way to retrieve and store the data into a "notes" variable in my custom object (such as an NSString object? I would think having multiple would exclude an NSString object as an option here, but maybe I'm wrong) or am I getting into a more complex area here (such as having to store it in an array of NSString objects, etc.)?
Any help would be appreciated!
You can get the data using -string, defined by NSText (e.g. NSString *savedString = [aTextView string])
Your save code can be put in your NSTextDelegate (read, delegate of the NSTextView, because it's the immediate superclass), in – textDidEndEditing: which will be called, well, when editing is finished (e.g. when the user clicks outside the view) or one of the other methods.
Then to reload the saved string if you emptied the text view or something, use [textView setString:savedString] before editing begins.
NSTextDelegate documentation: here.
I'm not sure what you mena when you say "store the contents of the box into a variable (array, etc.) Are you hoping for an array of custom notes? Text views store a string of data, so the easiest way of storing its value is using one string; if you need an array of notes you'd have to split the string value into different paragraphs, which shouldn't be too hard.
For a word processor I am writing I need to know sometimes the caret coordinates (the reason is long and uninteresting for the question itself). I writing the app. in Objective-C. I don't want to make calls to JavaScript and I don't want to make "tricks" like altering the DOM to get the caret coordinates (one solution would be to insert an empty span at the caret position and measure it bounding box). I've searched for methods that get the selected domrange bounding box with no success.
The only thing I found was a caretRectAtNode:offset:affinity in WebCoreFrameBridge (and other methods that seem to do what I want). So I see basically two answers to my question
1) There is a magic method in WebView that I am not considering
2) Tell me how to call methods inside WebCoreFrameBridge using Obj-C, and having a reference to a WebView/Frame/etc.