diff --git a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewAdapter.java b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewAdapter.java index 03608247fc1..8d64740fa44 100644 --- a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewAdapter.java +++ b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewAdapter.java @@ -99,12 +99,6 @@ public void onBindViewHolder(@NonNull ListViewHolder holder, int position) // Update ListViewHolder with new model data. // TODO: Optimize `bind()`. holder.bind(item, selected); - - // Handle ListView markers. - final ListViewProxy listViewProxy = item.getListViewProxy(); - if (listViewProxy != null) { - listViewProxy.handleMarker(item); - } } /** diff --git a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewHolder.java b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewHolder.java index 1ff92b9957e..d88c0529b6d 100644 --- a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewHolder.java +++ b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewHolder.java @@ -92,6 +92,7 @@ public void bind(final ListItemProxy proxy, final boolean selected) // Update model proxy holder. this.proxy = new WeakReference<>(proxy); + proxy.setHolder(this); // Obtain ListView proxy for item. final ListViewProxy listViewProxy = proxy.getListViewProxy(); @@ -244,8 +245,6 @@ public void bind(final ListItemProxy proxy, final boolean selected) setHeaderFooter(listViewProxy, sectionProperties, false, true); } } - - proxy.setHolder(this); } /** diff --git a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewProxy.java b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewProxy.java index 92d8dd1a51d..f14d8e353a0 100644 --- a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewProxy.java +++ b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/ListViewProxy.java @@ -22,9 +22,6 @@ import android.app.Activity; import android.view.View; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import ti.modules.titanium.ui.UIModule; import ti.modules.titanium.ui.widget.TiUIListView; @@ -433,67 +430,62 @@ protected TiUIView handleGetView() } /** - * Determine if `marker` event should be fired for specified item. - * - * @param item Item to handle for `marker` event. + * Determine if `marker` event should be fired. */ - public void handleMarker(ListItemProxy item) + public void handleMarkers() { - if (item != null) { - final Object parent = item.getParent(); - - if (parent instanceof ListSectionProxy) { - final ListSectionProxy section = (ListSectionProxy) parent; - final int sectionIndex = getIndexOfSection(section); - - if (markers.containsKey(sectionIndex)) { - - // Found marker for current section. - final Set itemIndexSet = markers.get(sectionIndex); - - final TiListView listView = getListView(); - if (listView == null) { - return; - } - final RecyclerView recyclerView = listView.getRecyclerView(); - if (recyclerView == null) { - return; - } - final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); - if (layoutManager == null) { - return; - } - - // Loop through markers for current section and determine visibility. - // Some items may not have scrolled into view. - for (Iterator i = itemIndexSet.iterator(); i.hasNext();) { - final Integer index = i.next(); - - final ListItemProxy markedItem = section.getListItemAt(index); - if (markedItem == null) { - continue; - } - final ListViewHolder markedHolder = markedItem.getHolder(); - if (markedHolder == null) { - continue; - } - final View markedItemView = markedHolder.itemView; - if (markedItemView == null || markedItemView.getLayoutParams() == null) { - continue; - } - final boolean isVisible = - layoutManager.isViewPartiallyVisible(markedItemView, false, true); - - if (isVisible) { - final KrollDict data = new KrollDict(); + final TiListView listView = getListView(); - // Create and fire marker event. - data.put(TiC.PROPERTY_SECTION_INDEX, sectionIndex); - data.put(TiC.PROPERTY_ITEM_INDEX, index); - fireEvent(TiC.EVENT_MARKER, data, false); + if (markers == null || markers.isEmpty() || listView == null) { + return; + } - // One time event, remove marker. - i.remove(); + final ListItemProxy[] items = + new ListItemProxy[] { listView.getFirstVisibleItem(), listView.getLastVisibleItem()}; + + for (final ListItemProxy item : items) { + if (item != null) { + final Object parent = item.getParent(); + + if (parent instanceof ListSectionProxy) { + final ListSectionProxy section = (ListSectionProxy) parent; + final int sectionIndex = getIndexOfSection(section); + + if (markers.containsKey(sectionIndex)) { + + // Found marker for current section. + final Set itemIndexSet = markers.get(sectionIndex); + + // Loop through markers for current section and determine visibility. + // Some items may not have scrolled into view. + for (Iterator i = itemIndexSet.iterator(); i.hasNext(); ) { + final Integer index = i.next(); + + final ListItemProxy markedItem = section.getListItemAt(index); + if (markedItem == null) { + continue; + } + final TiUIView markedView = markedItem.peekView(); + if (markedView == null) { + continue; + } + final View markedNativeView = markedView.getNativeView(); + if (markedNativeView == null) { + continue; + } + final boolean isVisible = markedNativeView.isShown(); + + if (isVisible) { + final KrollDict data = new KrollDict(); + + // Create and fire marker event. + data.put(TiC.PROPERTY_SECTION_INDEX, sectionIndex); + data.put(TiC.PROPERTY_ITEM_INDEX, index); + fireEvent(TiC.EVENT_MARKER, data, false); + + // One time event, remove marker. + i.remove(); + } } } } diff --git a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/TiListView.java b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/TiListView.java index ef01ea0f6af..0df7247e750 100644 --- a/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/TiListView.java +++ b/android/modules/ui/src/java/ti/modules/titanium/ui/widget/listview/TiListView.java @@ -66,7 +66,17 @@ public TiListView(ListViewProxy proxy) this.recyclerView.setFocusable(true); this.recyclerView.setFocusableInTouchMode(true); this.recyclerView.setBackgroundColor(Color.TRANSPARENT); - this.recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + this.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()) { + + @Override + public void onLayoutCompleted(RecyclerView.State state) + { + super.onLayoutCompleted(state); + + // Process markers after layout. + proxy.handleMarkers(); + } + }); this.recyclerView.setFocusableInTouchMode(false); // Add listener to fire scroll events. @@ -79,7 +89,10 @@ public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newStat if (isScrolling && newState == RecyclerView.SCROLL_STATE_IDLE) { isScrolling = false; - proxy.fireSyncEvent(TiC.EVENT_SCROLLEND, generateScrollPayload()); + + if (proxy.hierarchyHasListener(TiC.EVENT_SCROLLEND)) { + proxy.fireSyncEvent(TiC.EVENT_SCROLLEND, generateScrollPayload()); + } } } @@ -96,11 +109,15 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) if (!isScrolling) { isScrolling = true; - proxy.fireSyncEvent(TiC.EVENT_SCROLLSTART, generateScrollPayload()); + + if (proxy.hierarchyHasListener(TiC.EVENT_SCROLLSTART)) { + proxy.fireSyncEvent(TiC.EVENT_SCROLLSTART, generateScrollPayload()); + } } // Only fire `scrolling` event upon direction change. - if (lastScrollDeltaY >= 0 && dy <= 0 || lastScrollDeltaY <= 0 && dy >= 0) { + if (proxy.hierarchyHasListener(TiC.EVENT_SCROLLING) + && (lastScrollDeltaY >= 0 && dy <= 0 || lastScrollDeltaY <= 0 && dy >= 0)) { final KrollDict payload = generateScrollPayload(); // Determine scroll direction. @@ -114,6 +131,9 @@ public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) } lastScrollDeltaY = dy; + + // Process markers. + proxy.handleMarkers(); } }); @@ -250,18 +270,12 @@ public void filterBy(String query) */ public KrollDict generateScrollPayload() { - final KrollDict payload = new KrollDict(); + final ListItemProxy firstVisibleProxy = getFirstVisibleItem(); final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); + final KrollDict payload = new KrollDict(); // Obtain first visible list item view. - final View firstVisibleView = - layoutManager.findViewByPosition(layoutManager.findFirstVisibleItemPosition()); - if (firstVisibleView != null) { - final ListViewHolder firstVisibleHolder = - (ListViewHolder) recyclerView.getChildViewHolder(firstVisibleView); - - // Obtain first visible list item proxy. - final ListItemProxy firstVisibleProxy = (ListItemProxy) firstVisibleHolder.getProxy(); + if (firstVisibleProxy != null) { payload.put(TiC.PROPERTY_FIRST_VISIBLE_ITEM, firstVisibleProxy); // Obtain first visible list item index in section. @@ -356,6 +370,50 @@ public ListItemProxy getAdapterItem(int index) return this.items.get(index); } + /** + * Obtain first visible list item proxy. + * + * @return ListItemProxy + */ + public ListItemProxy getFirstVisibleItem() + { + final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); + final View firstVisibleView = + layoutManager.findViewByPosition(layoutManager.findFirstVisibleItemPosition()); + + if (firstVisibleView != null) { + final ListViewHolder firstVisibleHolder = + (ListViewHolder) recyclerView.getChildViewHolder(firstVisibleView); + + // Obtain first visible list item proxy. + return (ListItemProxy) firstVisibleHolder.getProxy(); + } + + return null; + } + + /** + * Obtain last visible list item proxy. + * + * @return ListItemProxy + */ + public ListItemProxy getLastVisibleItem() + { + final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); + final View lastVisibleView = + layoutManager.findViewByPosition(layoutManager.findLastVisibleItemPosition()); + + if (lastVisibleView != null) { + final ListViewHolder lastVisibleHolder = + (ListViewHolder) recyclerView.getChildViewHolder(lastVisibleView); + + // Obtain last visible list item proxy. + return (ListItemProxy) lastVisibleHolder.getProxy(); + } + + return null; + } + /** * Determine if table results are filtered by query. *