Closed thaidmfinnick closed 5 months ago
Oh I find a way to use ListViewObserver
and do not need CustomScrollView, so I can use ChatScrollObserver
, the my only problem is can I keep current position of one of my child update height, (Like children of 1 thread have new messages and scroll cannot keep position). Can I do some workaround for this situation to lock this scroll position?
Thank you!
You can complete it by setting the model to ChatScrollObserverHandleMode.specified
and specifying the indexes of the reference items before and after inserting the message.
Assume that you are currently changing the content of the item with index 0, then the index of the reference item before and after the change can be specified as 1.
chatObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
refItemRelativeIndex: 1,
refItemRelativeIndexAfterUpdate: 1,
);
final model = chatModels[0];
final newModel = ChatModel(
isOwn: model.isOwn,
content: model.content + '123abc',
);
chatModels[0] = newModel;
setState(() {});
See 3.4、Specifies the referenced item for more information.
Thanks for quick response, I have tried but it's not working, to not misunderstand I record a video below:
I have many threads, when 1 thread is update with new message, the scroll position is jump follow, the update messages are children of thread so I guess the index of the reference item is still 0 and not change. I try use refItem: 0 but it stills not working.
I have successfully insert new thread(not messages children of thread) without scroll position but this case isn't.
Oh, you misunderstood. The reference item should not be the item whose content has changed, but item that do not change.
For example, in thread0, the content of its children has changed, then the reference should be thread1/thread2 etc.
chatObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
refItemRelativeIndex: 1, // or 2...
refItemRelativeIndexAfterUpdate: 1, // or 2...
);
If you insert a new thread, the original thread0 will become thread1, and the new thread will become thread0. In this scenario, what changes is the new thread, and what remains unchanged is all the original threads. In this case, the reference thread can be the original thread0.
chatObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
refItemRelativeIndex: 0, // The index of original thread0 before inserting a new thread.
refItemRelativeIndexAfterUpdate: 1, // The index of original thread0 after inserting a new thread.
);
It is worth noting that the reference thread/children needs to be rendered before and after the change.
I try and succeedddd, thank you very muchhh! Before closing issue, I have one more question, what actually refItemRelativeIndex
use for?
And if 1 item hide 50% height, it's can be treat as display in screen? (I want to make sure to identify correct relative index)
what actually refItemRelativeIndex use for?
As shown in the following code, the refItemRelativeIndex
is actually a relative index of reference item, used to find the actual index of the item and obtain the layoutOffset
before the change.
And refItemRelativeIndexAfterUpdate
is used to find the actual index of the item and obtain the layoutOffset
after the change.
By subtracting the two, we can calculate how much offset needs to be adjusted after the change.
And if 1 item hide 50% height, it's can be treat as display in screen?
Yes, you should be able to understand it well after reading the picture below.
Very informative, so what if I choose refItemRelativeIndex outside of screen? I test but cannot see the differences. Also, when I test, the child with (current index = refItemRelativeIndex) will keep scroll when I update other child above? is it correct with logic?
I will close this issue after your answer.
P/s: I really appreciate your unfailing support and I have sent you a small gift as my thankss, have you received it??
so what if I choose refItemRelativeIndex outside of screen?
You can use the refItemRelativeIndex
outside of screen, as long as it is rendered before and after the change, but I still recommend that you use the index of the unchanged child closest to the changed child as much as possible.
when I test, the child with (current index = refItemRelativeIndex) will keep scroll when I update other child above? is it correct with logic?
I think this may be caused by the current offset of the ListView not exceeding fixedPositionOffset
, which you need to check.
See 3.1、Basic usage for more information.
I have sent you a small gift as my thankss, have you received it??
I received your gift, thank you very much. 😁
close as resolved!
@LinXunFeng, Everything is work as expected, only 1 case I show in video:
my piece code for test:
chatObserver.fixedPositionOffset = -1
chatObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
refItemRelativeIndex: 2,
refItemRelativeIndexAfterUpdate: 2
);
I choose refItemRelativeIndex = 2
, it means, scroll will not change at index 2 from viewport, right? So as my understand, when child at index 0, and 1 in viewport update, it will scroll upward instead of scroll downward in video demo. Do you know the reason? Correct me if I'm wrong. Thankss!
Based on your video, I guess the reserve
of your ListView should be true, so the relative indexes are also in reverse order.
When the content of child2 changes, the refItemRelativeIndex
you specify is also 2. After comparing before and after, the offset of child2 has not changed.
When the content of child1 changes, child2 is affected by child1, the child2's offset increases. However, due to the keep position functionality acts on child2, so what you see is that child1 increases downward.
No, the ListView I setup is not reverse, it's normal listview.
chatObserver.fixedPositionOffset = -1;
...
final result = await observerController.dispatchOnceObserve(
isForce: true,
isDependObserveCallback: false,
);
final displayingFirstChildIndex = result.observeResult?.firstChild?.index ?? 0;
final model = observerController.observeFirstItem();
final cacheFirstChildIndex = model?.index ?? 0;
final delta = displayingFirstChildIndex - cacheFirstChildIndex;
refItemRelativeIndex = 2 + delta;
chatObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
refItemRelativeIndex: refItemRelativeIndex,
refItemRelativeIndexAfterUpdate: refItemRelativeIndex,
);
Adjust the code and try it.
Yeah, it's work, only some situations, although I always listen and lock position to last display relative index, it's still scroll downward like in video, but after I scroll up a little bit, it's correct again. I'm not sure but it means to you in this situation?
Is your refItemRelativeIndex
always 1?
No, I change depends on last display relative index, if my view has [0, 1, 2], I will lock 2, if [0, 1], I will lock 1.
I don't know it's a bug, or not. but i will show in video below:
I have 3 threads in view => I lock position on last relative index: 2 I type on thread with index 1 If first thread have 100% visibility: => I type in thread 1 and thread 1 will jump as I expected But I scroll down to hide first thread only a little => I type and it's scroll down
My teammates and I are discussing about weird situation. It's about calculation offset, right?
This seem strange. You need to confirm the index of the first thread currently being displayed through the following code.
final result = await observerController.dispatchOnceObserve(
isForce: true,
isDependObserveCallback: false,
);
final displayingFirstChildIndex = result.observeResult?.firstChild?.index ?? 0;
debugPrint('displayingFirstChildIndex -- $displayingFirstChildIndex');
Have you set leadingOffset
or dynamicLeadingOffset
?
Have you set leadingOffset or dynamicLeadingOffset?
No i'm not.
You need to confirm the index of the first thread currently being displayed through the following code.
Oh, do I miss something? displayingFirstChildIndex
change? It must the same!
This may be an illusion. Have you set paddingBottom for thread to implement separator?
To confirm this, you can set a background color for the thread and print its displayPercentage
.
final result = await observerController.dispatchOnceObserve(
isForce: true,
isDependObserveCallback: false,
);
final firstChild = result.observeResult?.firstChild;
final index = firstChild?.index ?? 0;
final displayPercentage = firstChild?.displayPercentage ?? 0;
debugPrint('firstChild -- $index - $displayPercentage');
This may be an illusion. Have you set paddingBottom for thread to implement separator?
I have marginBottom: 24.
It stills weird, although indexLock = 2
, it's still scroll down. As your code you guide me, I print and only 3 items in list. You can see details in video:
Do you calculate anything related to first child with 50% percentage? I test when first child has displayPercentage around > 50%, thread 1 will scroll down, else if will scroll up (displayPercentage = 100% it will scroll up too).
I want it scroll up because I have locked scroll position to last display relative index.
I’m not sure where the problem lies just by watching the video. You can debug the following code breakpoints in chat_observer_scroll_physics_mixin.dart
.
Note that the keep position functionality will only take effect when you go to the third point.
Or can you provide a reproducible demo?
Oke, let me try to reproduce based on example. I will response as soon as possible! Thanks
@LinXunFeng,
I can reproduce my issue in create a demo file in example in your repo, I have forked and you can test. I put my reproducable case in my_test.dart
. Do I need create another issue?
Step to reproduce I have put in my_test.dart
, and video below:
https://github.com/thaidmfinnick/flutter_scrollview_observer
Do I need create another issue?
No, I think it's the same issue.
Please adjust the code as follows and try again.
int lastRelativeIndex = 1;
+ int currentFirstChildIndex = 0;
onObserve: (result) {
+ currentFirstChildIndex = result.firstChild?.index ?? 0;
lastRelativeIndex = result.displayingChildIndexList.length - 1;
},
floatingActionButton: FloatingActionButton(
onPressed: () {
print('lastRelativeIndex:$lastRelativeIndex');
chatScrollObserver.fixedPositionOffset = -1;
+ final model = observerController.observeFirstItem();
+ final cacheFirstChildIndex = model?.index ?? 0;
+ final delta = currentFirstChildIndex - cacheFirstChildIndex;
+ final refItemRelativeIndex = lastRelativeIndex + delta;
chatScrollObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
- refItemRelativeIndex: lastRelativeIndex,
- refItemRelativeIndexAfterUpdate: lastRelativeIndex,
+ refItemRelativeIndex: refItemRelativeIndex,
+ refItemRelativeIndexAfterUpdate: refItemRelativeIndex,
);
setState(() {
heightForMid += 50;
});
},
child: Icon(Icons.add)),
Oh my god, it's work perfect, you are magician. Why cache is different in this case?
First of all, I'm sorry. There was a slight mistake in yesterday's picture. I misled you. 😅
As shown in the picture above, observeFirstItem
will get the first rendered item, even if it is off-screen. Currently, the internal logic of keeping the position functionality also uses observeFirstItem
.
Therefore, in order to achieve the relative index logic mentioned yesterday, I used delta
to correct.
In the next version, I will add a new parameter to provide this correction logic, so that everyone does not have to correct it by themselves.
Ok, I understand your idea, all my weird questions was answered very carefully by you, and again thank you very much for your unfailing support. I will follow your repos, and use it.
Respect and see you again in other issues!
Version 1.20.0 has been released.
You can adjust the code without delta
as follows.
final refItemIndex = currentThreadIndex + 1;
chatObserver.standby(
mode: ChatScrollObserverHandleMode.specified,
refIndexType: ChatScrollObserverRefIndexType.itemIndex,
refItemIndex: refItemIndex,
refItemIndexAfterUpdate: refItemIndex,
);
Thanks! I have tested your above code you provide for my project and it works perfect. You divide into 3 specific cases: relativeIndexStartFromCacheExtent
, relativeIndexStartFromDisplaying
and itemIndex
. So clear to me!
Platforms
macOS
Description
Hi, thank for very useful library in Flutter World!
I want to use feature of listView is: fixed to the current chat position for CustomScrollView? Is it possible?
Thank you and look forward to seeing your response!
Why
My final desire feature is to keep scroll when elements of custom scroll view change index, resize. I find this library and it's very clear to me, and I go half of road to complete this feature. I found this wiki here to handle keep scroll with
ListObserverController
.