IOS7 TextKit: выравнивание маркеров
Я пишу приложение только для iOS 7, и я пытаюсь получить достойное форматирование на пулевых точках в не редактируемом UITextView.
Легко просто вставить символ точки пули, но, конечно, левого отступа не последует. Какой самый простой способ для iOS 7 установить левый отступ после точки маркера?
Спасибо заранее,
Франк
Ответы
Ответ 1
Ниже этого кода я использую, чтобы установить маркированный абзац. Это происходит прямо из рабочего приложения и используется для применения стиля ко всему абзацу в ответ на щелчок пользователем кнопки форматирования. Я попытался включить все зависимые методы, но, возможно, пропустил некоторые из них.
Обратите внимание, что я устанавливаю большинство отступов в сантиметрах и, следовательно, использую функции преобразования в конце списка.
Я также проверяю наличие символа табуляции (без ключа на iOS!) и автоматически вставляю тире и вкладку.
Если вам нужен только стиль абзаца, посмотрите на последние несколько методов, где устанавливается firstLineIndent и т.д.
Обратите внимание, что эти вызовы все обернуты в [textStorage beginEditing/endEditing]
. Несмотря на то, что (IBAction) ниже метод не получает непосредственно объект UI.
- (IBAction) styleBullet1:(id)sender
{
NSRange charRange = [self rangeForUserParagraphAttributeChange];
NSTextStorage *myTextStorage = [self textStorage];
// Check for "-\t" at beginning of string and add if not found
NSAttributedString *attrString = [myTextStorage attributedSubstringFromRange:charRange];
NSString *string = [attrString string];
if ([string rangeOfString:@"\t"].location == NSNotFound) {
NSLog(@"string does not contain tab so insert one");
NSAttributedString * aStr = [[NSAttributedString alloc] initWithString:@"-\t"];
// Insert a bullet and tab
[[self textStorage] insertAttributedString:aStr atIndex:charRange.location];
} else {
NSLog(@"string contains tab");
}
if ([self isEditable] && charRange.location != NSNotFound)
{
[myTextStorage setAttributes:[self bullet1Style] range:charRange];
}
}
- (NSDictionary*)bullet1Style
{
return [self createStyle:[self getBullet1ParagraphStyle] font:[self normalFont] fontColor:[UIColor blackColor] underlineStyle:NSUnderlineStyleNone];
}
- (NSDictionary*)createStyle:(NSParagraphStyle*)paraStyle font:(UIFont*)font fontColor:(UIColor*)color underlineStyle:(int)underlineStyle
{
NSMutableDictionary *style = [[NSMutableDictionary alloc] init];
[style setValue:paraStyle forKey:NSParagraphStyleAttributeName];
[style setValue:font forKey:NSFontAttributeName];
[style setValue:color forKey:NSForegroundColorAttributeName];
[style setValue:[NSNumber numberWithInt: underlineStyle] forKey:NSUnderlineStyleAttributeName];
FLOG(@" font is %@", font);
return style;
}
- (NSParagraphStyle*)getBullet1ParagraphStyle
{
NSMutableParagraphStyle *para;
para = [self getDefaultParagraphStyle];
NSMutableArray *tabs = [[NSMutableArray alloc] init];
[tabs addObject:[[NSTextTab alloc] initWithTextAlignment:NSTextAlignmentLeft location:[self ptsFromCMF:1.0] options:nil]];
//[tabs addObject:[[NSTextTab alloc] initWithType:NSLeftTabStopType location:[self ptsFromCMF:1.0]]];
[para setTabStops:tabs];
[para setDefaultTabInterval:[self ptsFromCMF:2.0]];
[para setFirstLineHeadIndent:[self ptsFromCMF:0.0]];
//[para setHeaderLevel:0];
[para setHeadIndent:[self ptsFromCMF:1.0]];
[para setParagraphSpacing:3];
[para setParagraphSpacingBefore:3];
return para;
}
- (NSMutableParagraphStyle*)getDefaultParagraphStyle
{
NSMutableParagraphStyle *para;
para = [[NSParagraphStyle defaultParagraphStyle]mutableCopy];
[para setTabStops:nil];
[para setAlignment:NSTextAlignmentLeft];
[para setBaseWritingDirection:NSWritingDirectionLeftToRight];
[para setDefaultTabInterval:[self ptsFromCMF:3.0]];
[para setFirstLineHeadIndent:0];
//[para setHeaderLevel:0];
[para setHeadIndent:0.0];
[para setHyphenationFactor:0.0];
[para setLineBreakMode:NSLineBreakByWordWrapping];
[para setLineHeightMultiple:1.0];
[para setLineSpacing:0.0];
[para setMaximumLineHeight:0];
[para setMinimumLineHeight:0];
[para setParagraphSpacing:6];
[para setParagraphSpacingBefore:3];
//[para setTabStops:<#(NSArray *)#>];
[para setTailIndent:0.0];
return para;
}
-(NSNumber*)ptsFromCMN:(float)cm
{
return [NSNumber numberWithFloat:[self ptsFromCMF:cm]];
}
-(float)ptsFromCMF:(float)cm
{
return cm * 28.3464567;
}
Ответ 2
Итак, я посмотрел вокруг, и вот извлеченный минимальный код из ответа Дункана, чтобы заставить его работать:
NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:yourLabel.text];
NSMutableParagraphStyle *paragrahStyle = [[NSMutableParagraphStyle alloc] init];
[paragrahStyle setParagraphSpacing:4];
[paragrahStyle setParagraphSpacingBefore:3];
[paragrahStyle setFirstLineHeadIndent:0.0f]; // First line is the one with bullet point
[paragrahStyle setHeadIndent:10.5f]; // Set the indent for given bullet character and size font
[attributedString addAttribute:NSParagraphStyleAttributeName value:paragrahStyle
range:NSMakeRange(0, [self.descriptionLabel.text length])];
yourLabel.attributedText = attributedString;
И вот результат этого в моем приложении:
![Quadratic Master]()
Ответ 3
Это самое легкое решение, которое я нашел:
let bulletList = UILabel()
let bulletListArray = ["line 1 - enter a bunch of lorem ipsum here so it wraps to the next line", "line 2", "line 3"]
let joiner = "\n"
var paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.headIndent = 10
paragraphStyle.firstLineHeadIndent = 0
let attributes = [NSParagraphStyleAttributeName: paragraphStyle]
let bulletListString = joiner.join(bulletListArray.map { "• \($0)" })
bulletList.attributedText = NSAttributedString(string: bulletListString, attributes: attributes)
теория, являющаяся каждой строкой в массиве, действует как "абзац", а стиль абзаца получает 0 отступ в первой строке, которая получает пулю, добавленную с помощью метода карты. Затем для каждой строки после нее получается отступ 10 px (отрегулируйте интервал для ваших метрик шрифта)
Ответ 4
Другие ответы полагаются на установку размера отступа с постоянным значением. Это означает, что вам придется вручную обновлять его, если вы меняете шрифты, и не будет работать, если вы используете Dynamic Type. К счастью, измерение текста легко.
Скажем, у вас есть текст и некоторые атрибуты:
NSString *text = @"• Some bulleted paragraph";
UIFont *font = [UIFont preferredFontForTextStyle:UIFontTextStyleBody];
NSDictionary *attributes = @{NSFontAttributeName: font};
Здесь, как измерить пулю и создать стиль абзаца соответственно:
NSString *bulletPrefix = @"• ";
CGSize size = [bulletPrefix sizeWithAttributes:attributes];
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.headIndent = size.width;
Мы вставляем это в наши атрибуты и создаем атрибутированную строку:
NSMutableDictionary *indentedAttributes = [attributes mutableCopy];
indentedAttributes[NSParagraphStyleAttributeName] = [paragraphStyle copy];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:text attributes:indentedAttributes];
Ответ 5
Swift 4
Я сделал расширение для NSAttributedString
, которое добавляет инициализатор удобства, который правильно отбрасывает разные типы списков.
extension NSAttributedString {
convenience init(listString string: String, withFont font: UIFont) {
self.init(attributedListString: NSAttributedString(string: string), withFont: font)
}
convenience init(attributedListString attributedString: NSAttributedString, withFont font: UIFont) {
guard let regex = try? NSRegularExpression(pattern: "^(\\d+\\.|[•\\-\\*])(\\s+).+$",
options: [.anchorsMatchLines]) else { fatalError() }
let matches = regex.matches(in: attributedString.string, options: [],
range: NSRange(location: 0, length: attributedString.string.utf16.count))
let nsString = attributedString.string as NSString
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
for match in matches {
let size = NSAttributedString(
string: nsString.substring(with: match.range(at: 1)) + nsString.substring(with: match.range(at: 2)),
attributes: [.font: font]).size()
let indentation = ceil(size.width)
let range = match.range(at: 0)
let paragraphStyle = NSMutableParagraphStyle()
if let style = attributedString.attribute(.paragraphStyle, at: 0, longestEffectiveRange: nil, in: range)
as? NSParagraphStyle {
paragraphStyle.setParagraphStyle(style)
}
paragraphStyle.tabStops = [NSTextTab(textAlignment: .left, location: indentation, options: [:])]
paragraphStyle.defaultTabInterval = indentation
paragraphStyle.firstLineHeadIndent = 0
paragraphStyle.headIndent = indentation
mutableAttributedString.addAttribute(.font, value: font, range: range)
mutableAttributedString.addAttribute(.paragraphStyle, value: paragraphStyle, range: range)
}
self.init(attributedString: mutableAttributedString)
}
}
Пример использования:
![Как используется инициализатор удобства]()
Количество пробелов после каждой пули и т.д. не имеет значения. Код будет вычислять соответствующую ширину углубления динамически в зависимости от количества вкладок или пробелов, которые вы решите иметь после пули.
Если атрибутная строка уже имеет стиль абзаца, инициализатор удобства сохранит параметры этого стиля абзаца и применит некоторые свои варианты.
Поддерживаемые символы: •, -, *, числа, за которыми следует период (например, 8.)
Ответ 6
Я сделал быстрое решение (Swift 2.3 на данный момент) на основе реализации Лукаса. У меня была небольшая проблема с линиями, у которых не было пуля, поэтому я сделал расширение, чтобы вы могли опционально передать диапазон, чтобы применить стиль абзаца.
extension String{
func getAllignedBulletPointsMutableString(bulletPointsRange: NSRange = NSMakeRange(0, 0)) -> NSMutableAttributedString{
let attributedString: NSMutableAttributedString = NSMutableAttributedString(string: self)
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.paragraphSpacing = 0
paragraphStyle.paragraphSpacingBefore = 0
paragraphStyle.firstLineHeadIndent = 0
paragraphStyle.headIndent = 7.5
attributedString.addAttributes([NSParagraphStyleAttributeName: paragraphStyle], range: bulletPointsRange)
return attributedString
}
}
Ответ 7
Вы можете сделать эту простую вещь с помощью Attributes Inspector, Select Indent Field и выполнить любые изменения, которые вы хотели бы сделать:)
![введите описание изображения здесь]()