Как остановить прокрутку NSScrollView вверх при горизонтальном изменении размера содержащегося NSTextView?
-
20-09-2019 - |
Вопрос
У меня есть NSTextView, в котором я хочу отображать горизонтальную полосу прокрутки.Судя по некоторым рекомендациям в Интернете, у меня большая часть работает, за исключением проблем с вертикальной полосой прокрутки.
Что я сделал, так это нашел ширину самой длинной строки (в пикселях с заданным шрифтом), а затем соответствующим образом изменил размеры NSTextContainer и NSTextView.Таким образом, горизонтальная полоса прокрутки соответствует ширине, а прокрутка вправо приведет к прокрутке до конца самой длинной строки текста.
После выполнения этой работы я заметил, что мой NSScrollView отображает и скрывает вертикальную полосу прокрутки, когда я печатаю.Я «исправил» эту проблему, установив для autohidesScrollers значение NO перед изменением размера, а затем YES после этого.Однако остается еще одна проблема: при наборе текста вертикальная полоса прокрутки большой палец прыгает к верху полосы прокрутки и возвращается в нужное место по мере ввода.Я набираю «a» <пробел>, он прыгает вверх, я снова нажимаю <пробел>, и он возвращается в нужное место.
Есть предположения?
Вот пример кода:
- (CGFloat)longestLineOfText
{
CGFloat longestLineOfText = 0.0;
NSRange lineRange;
NSString* theScriptText = [myTextView string];
NSDictionary* attributesDict = [NSDictionary dictionaryWithObject:scriptFont forKey:NSFontAttributeName]; //scriptFont is a instance variable
NSUInteger characterIndex = 0;
NSUInteger stringLength = [theScriptText length];
while (characterIndex < stringLength) {
lineRange = [theScriptText lineRangeForRange:NSMakeRange(characterIndex, 0)];
NSSize lineSize = [[theScriptText substringWithRange:lineRange] sizeWithAttributes:attributesDict];
longestLineOfText = max(longestLineOfText, lineSize.width);
characterIndex = NSMaxRange(lineRange);
}
return longestLineOfText;
}
// ----------------------------------------------------------------------------
- (void)updateMyTextViewWidth
{
static CGFloat previousLongestLineOfText = 0.0;
CGFloat currentLongestLineOfText = [self longestLineOfText];
if (currentLongestLineOfText != previousLongestLineOfText) {
BOOL shouldStopBlinkingScrollBar = (previousLongestLineOfText < currentLongestLineOfText);
previousLongestLineOfText = currentLongestLineOfText;
NSTextContainer* container = [myTextView textContainer];
NSScrollView* scrollView = [myTextView enclosingScrollView];
if (shouldStopBlinkingScrollBar) {
[scrollView setAutohidesScrollers:NO];
}
CGFloat padding = [container lineFragmentPadding];
NSSize size = [container containerSize];
size.width = currentLongestLineOfText + padding * 2;
[container setContainerSize:size];
NSRect frame = [myTextView frame];
frame.size.width = currentLongestLineOfText + padding * 2;
[myTextView setFrame:frame];
if (shouldStopBlinkingScrollBar) {
[scrollView setAutohidesScrollers:YES];
}
}
}
Решение
Спасибо Россу Картеру почта на Список разработчиков Cocoa, я решил эту проблему.
А.Вам необходимо настроить текстовое представление для поддержки горизонтальной прокрутки:
- (void)awakeFromNib {
[myTextView setHorizontallyResizable:YES];
NSSize tcSize = [[myTextView textContainer] containerSize];
tcSize.width = FLT_MAX;
[[myTextView textContainer] setContainerSize:tcSize];
[[myTextView textContainer] setWidthTracksTextView:NO];
}
Б.Вам необходимо обновлять ширину текстового представления по мере его изменения, иначе горизонтальная полоса прокрутки не будет обновляться должным образом:
- (void)textDidChange:(NSNotification *)notification
{
[self updateTextViewWidth];
}
- (CGFloat)longestLineOfText
{
CGFloat longestLineOfText = 0.0;
NSLayoutManager* layoutManager = [myTextView layoutManager];
NSRange lineRange;
NSUInteger glyphIndex = 0;
NSUInteger glyphCount = [layoutManager numberOfGlyphs];
while (glyphIndex < glyphCount) {
NSRect lineRect = [layoutManager lineFragmentUsedRectForGlyphAtIndex:glyphIndex
effectiveRange:&lineRange
withoutAdditionalLayout:YES];
longestLineOfText = max(longestLineOfText, lineRect.size.width);
glyphIndex = NSMaxRange(lineRange);
}
return longestLineOfText;
}
// ----------------------------------------------------------------------------
- (void)updateTextViewWidth
{
static CGFloat previousLongestLineOfText = 0.0;
CGFloat currentLongestLineOfText = [self longestLineOfText];
if (currentLongestLineOfText != previousLongestLineOfText) {
previousLongestLineOfText = currentLongestLineOfText;
NSTextContainer* container = [myTextView textContainer];
CGFloat padding = [container lineFragmentPadding];
NSRect frame = [myTextView frame];
frame.size.width = currentLongestLineOfText + padding * 2;
[myTextView setFrame:frame];
}
}