OK、UITextView
に問題があります。問題は次のとおりです。
UITextView
にテキストを追加します。次に、ユーザーはダブルクリックして何かを選択します。次に、UITextView
(上記のようにプログラムで)のテキストを変更し、UITextView
をカーソルがあるページの下部までスクロールします。
ただし、ユーザーがクリックした場所ではありません。ユーザーがどこをクリックしたかに関係なく、常にUITextView
の一番下までスクロールします。
私の質問は次のとおりです。テキストを変更するたびにUITextView
を強制的に一番上にスクロールさせるにはどうすればよいですか? contentOffset
とscrollRangeToVisible
を試しました。どちらも動作しません。
任意の提案をいただければ幸いです。
UITextView*note;
[note setContentOffset:CGPointZero animated:YES];
これは私のためにそれを行います。
Swiftバージョン(Xcode 9.3のiOS 11を搭載したSwift 4.1):
note.setContentOffset(.zero, animated: true)
IOS 8でこの問題が発生した場合、UITextView's
テキストプロパティを設定し、scrollRangeToVisible
をNSRange
で呼び出し、location:0
、length:0
、働いた。テキストビューは編集できず、選択可能と選択不可能の両方をテストしました(どちらの設定も結果に影響しませんでした)。 Swiftの例:
myTextView.text = "Text that is long enough to scroll"
myTextView.scrollRangeToVisible(NSRange(location:0, length:0))
そして、ここに私の解決策があります...
override func viewDidLoad() {
textView.scrollEnabled = false
textView.text = "your text"
}
override func viewDidAppear(animated: Bool) {
textView.scrollEnabled = true
}
呼び出し中
scrollRangeToVisible(NSMakeRange(0, 0))
動作しますが、呼び出します
override func viewDidAppear(animated: Bool)
テキストビューを編集できないHTMLでattributedStringを使用していました。コンテンツオフセットの設定も機能しませんでした。これは私のために働いた:スクロールを無効にし、テキストを設定し、スクロールを再び有効にする
[yourTextView setScrollEnabled:NO];
yourTextView.text = yourtext;
[yourTextView setScrollEnabled:YES];
これらのソリューションはどれも役に立たず、ソリューションをつなぎ合わせるのに時間がかかりすぎたので、最終的には解決しました。
override func viewWillAppear(animated: Bool) {
dispatch_async(dispatch_get_main_queue(), {
let desiredOffset = CGPoint(x: 0, y: -self.textView.contentInset.top)
self.textView.setContentOffset(desiredOffset, animated: false)
})
}
これは、このコントロールのデフォルトの動作ではないというのは本当にばかげています。
これが他の人の助けになるといいのですが。
私はあなたの質問を理解しているかどうかはわかりませんが、単にビューを一番上までスクロールしようとしていますか?もしそうならあなたはすべき
[textview scrollRectToVisible:CGRectMake(0,0,1,1) animated:YES];
IOS 10およびSwift 3の場合:
override func viewDidLoad() {
super.viewDidLoad()
textview.isScrollEnabled = false
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textView.isScrollEnabled = true
}
最新バージョンのSwiftおよびiOSに問題があるかどうかはわかりませんが、.
テキストビューが適切に表示され、ユーザーにスクロールアニメーションが表示されない更新された回答があります。
override func viewWillAppear(animated: Bool) {
dispatch_async(dispatch_get_main_queue(), {
self.introductionText.scrollRangeToVisible(NSMakeRange(0, 0))
})
それが私がやった方法です
スウィフト4:
extension UITextView {
override open func draw(_ rect: CGRect)
{
super.draw(rect)
setContentOffset(CGPoint.zero, animated: false)
}
}
これは、textViewが画面に表示される前に上にスクロールされるため、iOS 9リリースでどのように機能したかです。
- (void)viewDidLoad
{
[super viewDidLoad];
textView.scrollEnabled = NO;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
textView.scrollEnabled = YES;
}
私の問題は、ビューが表示されたときにtextViewが上にスクロールするように設定することです。 iOS 10.3.2、およびSwift 3。
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// It doesn't work. Very strange.
self.textView.setContentOffset(CGPoint.zero, animated: false)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// It works, but with an animation effection.
self.textView.setContentOffset(CGPoint.zero, animated: false)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// It works.
self.textView.contentOffset = CGPoint.zero
}
[txtView setContentOffset:CGPointMake(0.0, 0.0) animated:YES];
このコード行は私に適しています。
前の回答を組み合わせて、今では動作するはずです:
talePageText.scrollEnabled = false
talePageText.textColor = UIColor.blackColor()
talePageText.font = UIFont(name: "Bradley Hand", size: 24.0)
talePageText.contentOffset = CGPointZero
talePageText.scrollRangeToVisible(NSRange(location:0, length:0))
talePageText.scrollEnabled = true
これを試して、カーソルをテキストの上部に移動します。
NSRange r = {0,0};
[yourTextView setSelectedRange:r];
それがどうなるかを見てください。すべてのイベントが発生した後、またはこれまでに実行したことが行われた後に、必ずこれを呼び出してください。
Swift 2回答:
textView.scrollEnabled = false
/* Set the content of your textView here */
textView.scrollEnabled = true
これにより、設定後にtextViewがテキストの最後までスクロールしないようにします。
In Swift 3 ::
viewWillLayoutSubviewsは、変更を加える場所です。 viewWillAppearも機能するはずですが、論理的にはlayoutはviewWillLayoutSubviewsで実行する必要があります。
メソッドに関しては、scrollRangeToVisibleとsetContentOffsetの両方が機能します。ただし、setContentOffsetでは、アニメーションをオフまたはオンにできます。
ITextViewの名前がyourUITextViewであると仮定します。コードは次のとおりです。
// Connects to the TextView in the interface builder.
@IBOutlet weak var yourUITextView: UITextView!
/// Overrides the viewWillLayoutSubviews of the super class.
override func viewWillLayoutSubviews() {
// Ensures the super class is happy.
super.viewWillLayoutSubviews()
// Option 1:
// Scrolls to a range of text, (0,0) in this very case, animated.
yourUITextView.scrollRangeToVisible(NSRange(location: 0, length: 0))
// Option 2:
// Sets the offset directly, optional animation.
yourUITextView.setContentOffset(CGPoint(x: 0, y: 0), animated: false)
}
これは私のために働いた
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.main.async {
self.textView.scrollRangeToVisible(NSRange(location: 0, length: 0))
}
}
-(void) viewDidAppear:(BOOL)animated{
[mytextView scrollRangeToVisible:NSMakeRange(0,0)];}
- (void)viewWillAppear:(BOOL)animated{
[mytextView scrollRangeToVisible:NSMakeRange(0,0)];}
ViewWillappear
はユーザーが気付く前に即座にそれを行いますが、ViewDidDisappear
セクションはそれを遅延的にアニメーション化します。[mytextView setContentOffset:CGPointZero animated:YES];
は時々動作しません(理由はわかりません)ので、代わりにscrollrangetovisibleを使用してください。これは私のために働いた。 RyanTCBの回答に基づいていますが、同じソリューションのObjective-Cバリアントです。
- (void) viewWillAppear:(BOOL)animated {
// For some reason the text view, which is a scroll view, did scroll to the end of the text which seems to hide the imprint etc at the beginning of the text.
// On some devices it is not obvious that there is more text when the user scrolls up.
// Therefore we need to scroll textView to the top.
[self.textView scrollRangeToVisible:NSMakeRange(0, 0)];
}
このコードを使用できます
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
textView.scrollRangeToVisible(NSMakeRange(0, 0))
}
問題解決:iOS = 10.2 Swift 3 UITextView
次の行を使用しました。
displayText.contentOffset.y = 0
私は問題を抱えていましたが、私の場合、textviewはカスタムビューのサブビューであり、ViewControllerに追加しました。解決策のどれも私のために働いた。この問題を解決するには、0.1秒の遅延を追加し、スクロールを有効にしました。それは私のために働いた。
textView.isScrollEnabled = false
..
textView.text = // set your text here
let dispatchTime = DispatchTime.now() + 0.1
DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
self.textView.isScrollEnabled = true
}
-(void)viewWillLayoutSubviews{
[super viewWillLayoutSubviews];
[textview setContentOffset:CGPointZero animated:NO];
}
[self.textView scrollRectToVisible:CGRectMake(0, 0, 320, self.textView.frame.size.height) animated:NO];
私にとっては、このコードはうまく機能します:
textView.attributedText = newText //or textView.text = ...
//this part of code scrolls to top
textView.contentOffset.y = -64
textView.scrollEnabled = false
textView.layoutIfNeeded() //if don't work, try to delete this line
textView.scrollEnabled = true
正確な位置にスクロールして画面の上部に表示するには、次のコードを使用します。
var scrollToLocation = 50 //<needed position>
textView.contentOffset.y = textView.contentSize.height
textView.scrollRangeToVisible(NSRange.init(location: scrollToLocation, length: 1))
ContentOffset.yを設定すると、テキストの最後までスクロールし、scrollRangeToVisibleがscrollToLocationの値までスクロールします。これにより、必要な位置がscrollViewの最初の行に表示されます。
この2行のソリューションを使用してみてください。
view.layoutIfNeeded()
textView.contentOffset = CGPointMake(textView.contentInset.left, textView.contentInset.top)
一部の人々がこの問題で問題を抱えている理由は、TextView
が現れる前にTextView
スクロール位置を設定しようとしているためだと思います。
TextView
がまだ表示されていない場合、スクロールするものはありません。
TextView
が最初に表示されるまで待ってから、次に示すようにviewDidAppear
メソッド内でスクロール位置を設定する必要があります。
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textView.setContentOffset(CGPoint.zero, animated: false)
}
ここに私のコードがあります。正常に動作します。
class MyViewController: ...
{
private offsetY: CGFloat = 0
@IBOutlet weak var textView: UITextView!
...
override viewWillAppear(...)
{
...
offsetY = self.textView.contentOffset.y
...
}
...
func refreshView() {
let offSetY = textView.contentOffset.y
self.textView.setContentOffset(CGPoint(x:0, y:0), animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
[unowned self] in
self.textView.setContentOffset(CGPoint(x:0, y:self.offSetY),
animated: true)
self.textView.setNeedsDisplay()
}
}
このコードは問題を解決し、textViewの最後までの不要な自動スクロールを回避するのにも役立ちます。テキストを直接textViewに設定する代わりに、メソッドsetTextPreservingContentOffset:
を使用します。
@interface ViewController () {
__weak IBOutlet UITextView *textView;
CGPoint lastContentOffset;
NSTimer *autoscrollTimer;
BOOL revertAnyContentOffsetChanges;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[textView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
- (void)dealloc
{
[textView removeObserver:self forKeyPath:@"contentOffset"];
}
- (void)setTextPreservingContentOffset:(NSString *)text
{
lastContentOffset = textView.contentOffset;
[autoscrollTimer invalidate];
revertAnyContentOffsetChanges = YES;
textView.text = text;
autoscrollTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(enableScrolling:) userInfo:nil repeats:NO];
autoscrollTimer.tolerance = 1;
}
- (void)enableScrolling:(NSTimer *)timer
{
revertAnyContentOffsetChanges = NO;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (revertAnyContentOffsetChanges && [keyPath isEqualToString:@"contentOffset"] && [[change valueForKey:@"new"] CGPointValue].y != lastContentOffset.y) {
[textView setContentOffset:lastContentOffset animated:NO];
}
}
@end
viewDidLayoutSubviews内で次を呼び出す必要がありました(viewDidLoad内の呼び出しは早すぎました):
myTextView.setContentOffset(.zero, animated: true)
IOS 9の私にとっては、メソッドscrollRangeToVisibleの属性付き文字列で動作しなくなりました(1行は太字フォントで、他の行は通常フォントでした)
だから私は使用する必要がありました:
textViewMain.attributedText = attributedString
textViewMain.scrollRangeToVisible(NSRange(location:0, length:0))
delay(0.0, closure: {
self.textViewMain.scrollRectToVisible(CGRectMake(0, 0, 10, 10), animated: false)
})
遅延は次のとおりです。
func delay(delay:Double, closure:()->Void) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
Drew_sのSwift 3バージョンは以前に答えました。これは、他のほとんどの答えを試した後、私のために働いた唯一のことです。
override func viewWillAppear(_ animated: Bool) {
DispatchQueue.main.async{
let desiredOffset = CGPoint(x: 0, y: -self.person_description.contentInset.top)
self.person_description.setContentOffset(desiredOffset, animated: false)
}
}
これは作業コードのカットアンドペーストでした。 person_descriptionをtextview変数に置き換えます。
ChallengerGuyの答えは、スクロールを再び有効にする前に短い遅延を追加すると、私の問題を完全に解決しました。遅延を追加する前に、PageControllerページはすべて、最初のページを除いてすべて修正されました。最初のページは、ユーザーがページを操作した後にも修正されます。遅延を追加すると、その最初のページのUITextViewスクロール位置も修正されました。
override open func viewDidLoad() {
super.viewDidLoad()
textView.isScrollEnabled = false
textView.text = textToScroll
... other stuff
}
override open func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Central().delay(0.5) {
self.textView.isScrollEnabled = true
}
}
(私のCentral()ファイルの遅延機能。)
func delay(_ delay: Double, closure:@escaping ()->()) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
closure()
}
}
Swiftこれを行う最もクリーンな方法は、UITextViewをサブクラス化し、この小さなトリックを使用することだと思います
import UIKit
class MyTextView: UITextView {
override var text: String! {
willSet {
isScrollEnabled = false
} didSet {
isScrollEnabled = true
}
}
}