Forum Archive

Scrolling to the end of a textview

kami

Hi,

i am trying to append some text to my textview field.
The text is really long but then i try to scroll to bottom in the textview. This i not working.

I used this code:

def appendtextview(text):
    v['viewtop']['textview1'].text = v['viewtop']['textview1'].text + str(text)
    v['viewtop']['textview1'].content_offset = (0, v['viewtop']['textview1'].content_size[1] - v['viewtop']['textview1'].height) 

Can someon help me with this?

Thanks a lot.

Cu kami

JonB

Try:
1) wrapping that method in an on_main_thread. That might ensure that when you set the text, the content size is also updated. I believe the content_size is probably old.
2) one thing we did in stash, was to add a slight ui.delay after setting text, to scroll to the desired location. I think we determined that content_size might not be immediately updated by the OS, so you have to wait.

JonB

@kami one other thing to try would be objc_util. This may be related to a long-standing iOS bug. The workaround suggested on SO is

-(void) scrollToBottom {
  [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
  [textView setScrollEnabled:NO];
  [textView setScrollEnabled:YES];
}

I haven't tried to convert this to python equivalent.

kami

Hi,

this was a good idea. The short delay with 0.5 sec is enough to get down to the last row.

Thanks a lot for the help.

Cu kami

mikael

@kami, good to hear. If that makes app feel sluggish in use, 0.1 sec works just as well.

kami

After testing a little bit, it is no running smoothly. When i scroll in the textview it is not going down to the end?

Can anyone maybe post a better version or an objc_util example?

Thanks a lot.

Cu kami

cvp

@kami try this

import ui
from objc_util import *

tv = ui.TextView()
tv.frame = (0,0,500,500)
tv.text = 'a'*12000

b = ui.ButtonItem()
b.title = 'bottom'
def b_action(sender):
    tvo = ObjCInstance(tv)
    tvo.scrollRangeToVisible_(NSRange(len(tv.text),0))
    tvo.setScrollingEnabled_(False)
    tvo.setScrollingEnabled_(True)
    pass
b.action = b_action
tv.right_button_items = (b,)

tv.present('sheet')
kami

Works much better, but only every second time. First time it scrolls to the end. The second time it scrolls to much down, so the textview is empty????

Cu kami

cvp

@kami With exactly this little script? For me, it is ok

kami

Hi,

after some testing it only works for me at everytime with a short delay of 0.4 sec.

Otherwise it comes to some errors. Is it possible to check first if the textview is reloaded and then scroll down?

Thanks a lot.

Cu kami

mikael

@kami, here’s an alternative approach. You can add a guard variable in update if you do not want to have it constantly ”running”.

import ui

class ScrollToBottomTextView(ui.View):

  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.tv = ui.TextView(
      frame=self.bounds,
      flex='WH'
    )
    self.add_subview(self.tv)
    self.update_interval = 1/60

  def update(self):
    self.tv.content_offset = (
      0, self.tv.content_size[1]-self.height)

if __name__ == '__main__':

  v = ScrollToBottomTextView()
  v.present()

  import requests
  text = requests.get('https://forum.omz-software.com/topic/5744/scrolling-to-the-end-of-a-textview').text
  lines = text.splitlines()
  i = 0

  def add_line():
    global lines, i
    v.tv.text += lines[i] + '\n'
    i += 1
    ui.delay(add_line, 0.5)

  ui.delay(add_line, 0.5)