Android RecyclerView曝光采集的实现方法

Lamaara ·
更新时间:2024-09-21
· 1207 次阅读

本文实例为大家分享了Android RecyclerView曝光采集的具体代码,供大家参考,具体内容如下

一、背景

近期pm提出需要统计首页商品的曝光亮,由于我们的首页是用的recylerview实现的,这里就来讲下如何使用监听recylerview的滚动事件来实现子view的曝光量统计,我们这里说的view都是列表中的子item条目(子view)

二、监听recylerview的滚动事件OnScrollListener

onScrollStateChanged:监听滚动状态
onScrolled:监听滚动

我们接下来的统计工作,就是拿这两个方法做文章。

//检测recylerview的滚动事件 recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {        @Override        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {            /*            我这里通过的是停止滚动后屏幕上可见view。如果滚动过程中的可见view也要统计,你可以根据newState去做区分            SCROLL_STATE_IDLE:停止滚动            SCROLL_STATE_DRAGGING: 用户慢慢拖动            SCROLL_STATE_SETTLING:惯性滚动            */            if (newState == RecyclerView.SCROLL_STATE_IDLE) {                .....            }        }        @Override        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {            super.onScrolled(recyclerView, dx, dy);           ........        }    });

首先再次明确下,我们要统计的是用户停止滑动时,显示在屏幕的上控件。所以我们要监测到onScrollStateChanged 方法中
newState == RecyclerView.SCROLL_STATE_IDLE 时,也就是用户停止滚动。然后在这里做文章

三、获取屏幕内可见条目的起始位置

这里的起始位置就是指我们屏幕当中最上面和最下面条目的位置。比如下图的0就是最上面的可见条目,3就是最下面的可见条目。我们次数的曝光view就是0,1,2,3 这个时候这四个条目显示在屏幕中。我们这时就要对这4个view的曝光量进行加1
那么接下来的重点就是要去获取屏幕内可见条目的起始位置。获取到起始位置后,当前屏幕里的可见条目就都能拿到了。
而recylerview的manager正好给我们提供的有对应的方法。
findFirstVisibleItemPosition()和findLastVisibleItemPosition() 看字面意思就能知道这时干嘛用的。
但是我们的manager不止LinearLayoutManager一种,所以我们要做下区分

//这里我们用一个数组来记录起始位置 int[] range = new int[2]; RecyclerView.LayoutManager manager = reView.getLayoutManager(); if (manager instanceof LinearLayoutManager) {     range = findRangeLinear((LinearLayoutManager) manager); } else if (manager instanceof GridLayoutManager) {     range = findRangeGrid((GridLayoutManager) manager); } else if (manager instanceof StaggeredGridLayoutManager) {     range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager); }

LinearLayoutManager和GridLayoutManager获取起始位置方法如下

private int[] findRangeLinear(LinearLayoutManager manager) {     int[] range = new int[2];     range[0] = manager.findFirstVisibleItemPosition();     range[1] = manager.findLastVisibleItemPosition();     return range; } private int[] findRangeGrid(GridLayoutManager manager) {     int[] range = new int[2];     range[0] = manager.findFirstVisibleItemPosition();     range[1] = manager.findLastVisibleItemPosition();     return range; }

StaggeredGridLayoutManager获取起始位置有点复杂,如下

private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager) {     int[] startPos = new int[manager.getSpanCount()];     int[] endPos = new int[manager.getSpanCount()];     manager.findFirstVisibleItemPositions(startPos);     manager.findLastVisibleItemPositions(endPos);     int[] range = findRange(startPos, endPos);     return range; } private int[] findRange(int[] startPos, int[] endPos) {    int start = startPos[0];     int end = endPos[0];     for (int i = 1; i < startPos.length; i++) {         if (start > startPos[i]) {             start = startPos[i];         }     }     for (int i = 1; i < endPos.length; i++) {         if (end < endPos[i]) {             end = endPos[i];         }     }     int[] res = new int[]{start, end};     return res; } 四、获取到起始位置以后,我们就根据位置获取到view及view中的数据

上面第三步拿到屏幕内可见条目的起始位置以后,我们就用一个for循环,获取当前屏幕内可见的所有子view

for (int i = range[0]; i <= range[1]; i++) {  View view = manager.findViewByPosition(i);   recordViewCount(view); }

recordViewCount是我自己写的用于获取子view内绑定数据的方法

//获取view绑定的数据 private void recordViewCount(View view) {     if (view == null || view.getVisibility() != View.VISIBLE ||             !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {         return;     }     int top = view.getTop();     int halfHeight = view.getHeight() / 2;     int screenHeight = UiUtils.getScreenHeight((Activity) view.getContext());     int statusBarHeight = UiUtils.getStatusBarHeight(view.getContext());     if (top < 0 && Math.abs(top) > halfHeight) {         return;     }     if (top > screenHeight - halfHeight - statusBarHeight) {         return;     }     //这里获取的是我们view绑定的数据,相应的你要去在你的view里setTag,只有set了,才能get     ItemData tag = (ItemData) view.getTag();     String key = tag.toString();     if (TextUtils.isEmpty(key)) {         return;     }     hashMap.put(key, !hashMap.containsKey(key) ? 1 : (hashMap.get(key) + 1));     Log.i("qcl0402", key + "----出现次数:" + hashMap.get(key)); }

这里有几点需要注意

这这里起始位置的view显示区域如果不超过50%,就不算这个view可见,进而也就不统计曝光。
我们通过view.getTag();获取view里的数据,必须在此之前setTag()数据,我这里setTag是在viewholder中把数据set进去的

到这里我们就实现了recylerview列表中view控件曝光量的统计了。下面贴出来完整的代码给大家

package com.example.qcl.demo.xuexi.baoguang; import android.app.Activity; import android.graphics.Rect; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.StaggeredGridLayoutManager; import android.text.TextUtils; import android.util.Log; import android.view.View; import com.example.qcl.demo.utils.UiUtils; import java.util.concurrent.ConcurrentHashMap; /**  * 2019/4/2 13:31  * author: qcl  * desc: 安卓曝光量统计工具类  * wechat:2501902696  */ public class ViewShowCountUtils {     //刚进入列表时统计当前屏幕可见views     private boolean isFirstVisible = true;     //用于统计曝光量的map     private ConcurrentHashMap<String, Integer> hashMap = new ConcurrentHashMap<String, Integer>();     /*      * 统计RecyclerView里当前屏幕可见子view的曝光量      *      * */     void recordViewShowCount(RecyclerView recyclerView) {         hashMap.clear();         if (recyclerView == null || recyclerView.getVisibility() != View.VISIBLE) {             return;         }         //检测recylerview的滚动事件         recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {             @Override             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {                 /*                 我这里通过的是停止滚动后屏幕上可见view。如果滚动过程中的可见view也要统计,你可以根据newState去做区分                 SCROLL_STATE_IDLE:停止滚动                 SCROLL_STATE_DRAGGING: 用户慢慢拖动                 SCROLL_STATE_SETTLING:惯性滚动                 */                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {                     getVisibleViews(recyclerView);                 }             }             @Override             public void onScrolled(RecyclerView recyclerView, int dx, int dy) {                 super.onScrolled(recyclerView, dx, dy);                 //刚进入列表时统计当前屏幕可见views                 if (isFirstVisible) {                     getVisibleViews(recyclerView);                     isFirstVisible = false;                 }             }         });     }     /*      * 获取当前屏幕上可见的view      * */     private void getVisibleViews(RecyclerView reView) {         if (reView == null || reView.getVisibility() != View.VISIBLE ||                 !reView.isShown() || !reView.getGlobalVisibleRect(new Rect())) {             return;         }         //保险起见,为了不让统计影响正常业务,这里做下try-catch         try {             int[] range = new int[2];             RecyclerView.LayoutManager manager = reView.getLayoutManager();             if (manager instanceof LinearLayoutManager) {                 range = findRangeLinear((LinearLayoutManager) manager);             } else if (manager instanceof GridLayoutManager) {                 range = findRangeGrid((GridLayoutManager) manager);             } else if (manager instanceof StaggeredGridLayoutManager) {                 range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager);             }             if (range == null || range.length < 2) {                 return;             }             Log.i("qcl0402", "屏幕内可见条目的起始位置:" + range[0] + "---" + range[1]);             for (int i = range[0]; i <= range[1]; i++) {                 View view = manager.findViewByPosition(i);                 recordViewCount(view);             }         } catch (Exception e) {             e.printStackTrace();         }     }     //获取view绑定的数据     private void recordViewCount(View view) {         if (view == null || view.getVisibility() != View.VISIBLE ||                 !view.isShown() || !view.getGlobalVisibleRect(new Rect())) {             return;         }         int top = view.getTop();         int halfHeight = view.getHeight() / 2;         int screenHeight = UiUtils.getScreenHeight((Activity) view.getContext());         int statusBarHeight = UiUtils.getStatusBarHeight(view.getContext());         if (top < 0 && Math.abs(top) > halfHeight) {             return;         }         if (top > screenHeight - halfHeight - statusBarHeight) {             return;         }         //这里获取的是我们view绑定的数据,相应的你要去在你的view里setTag,只有set了,才能get         ItemData tag = (ItemData) view.getTag();         String key = tag.toString();         if (TextUtils.isEmpty(key)) {             return;         }         hashMap.put(key, !hashMap.containsKey(key) ? 1 : (hashMap.get(key) + 1));         Log.i("qcl0402", key + "----出现次数:" + hashMap.get(key));     }     private int[] findRangeLinear(LinearLayoutManager manager) {         int[] range = new int[2];         range[0] = manager.findFirstVisibleItemPosition();         range[1] = manager.findLastVisibleItemPosition();         return range;     }     private int[] findRangeGrid(GridLayoutManager manager) {         int[] range = new int[2];         range[0] = manager.findFirstVisibleItemPosition();         range[1] = manager.findLastVisibleItemPosition();         return range;     }     private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager) {         int[] startPos = new int[manager.getSpanCount()];         int[] endPos = new int[manager.getSpanCount()];         manager.findFirstVisibleItemPositions(startPos);         manager.findLastVisibleItemPositions(endPos);         int[] range = findRange(startPos, endPos);         return range;     }     private int[] findRange(int[] startPos, int[] endPos) {         int start = startPos[0];         int end = endPos[0];         for (int i = 1; i < startPos.length; i++) {             if (start > startPos[i]) {                 start = startPos[i];             }         }         for (int i = 1; i < endPos.length; i++) {             if (end < endPos[i]) {                 end = endPos[i];             }         }         int[] res = new int[]{start, end};         return res;     } }



方法 recyclerview Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章