I encountered this problem mylsef. The way I solved it was to do a scroll container and then do:
func _scroll_to_text_edit(text_edit : TextEdit) -> void:
scroll_container.ensure_control_visible(text_edit)
For the height problem you have to do it inside a _process() so it runs in every frame:
func _process(_delta: float) -> void:
if DisplayServer.has_feature(DisplayServer.FEATURE_VIRTUAL_KEYBOARD):
var keyboard_height = DisplayServer.virtual_keyboard_get_height()
if keyboard_height > 0:
self.size.y = get_viewport_rect().size.y - keyboard_height
else:
self.size.y = get_viewport_rect().size.y
You can check my lame implementation here: https://github.com/4Robato/track-your-counters/blob/main/UI/main.gd
It's been a while and I forgot a bit the details and I can't take a deeper look now but I hope this helps!