最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android?RecyclerView曝光采集的實(shí)現(xiàn)方法

 更新時(shí)間:2022年01月17日 13:34:23   作者:最萌小熊貓  
這篇文章主要為大家詳細(xì)介紹了Android?RecyclerView曝光采集的實(shí)現(xiàn)方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Android RecyclerView曝光采集的具體代碼,供大家參考,具體內(nèi)容如下

一、背景

近期pm提出需要統(tǒng)計(jì)首頁商品的曝光亮,由于我們的首頁是用的recylerview實(shí)現(xiàn)的,這里就來講下如何使用監(jiān)聽recylerview的滾動(dòng)事件來實(shí)現(xiàn)子view的曝光量統(tǒng)計(jì),我們這里說的view都是列表中的子item條目(子view)

二、監(jiān)聽recylerview的滾動(dòng)事件OnScrollListener

onScrollStateChanged:監(jiān)聽滾動(dòng)狀態(tài)
onScrolled:監(jiān)聽滾動(dòng)

我們接下來的統(tǒng)計(jì)工作,就是拿這兩個(gè)方法做文章。

//檢測(cè)recylerview的滾動(dòng)事件
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
? ? ? ?@Override
? ? ? ?public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
? ? ? ? ? ?/*
? ? ? ? ? ?我這里通過的是停止?jié)L動(dòng)后屏幕上可見view。如果滾動(dòng)過程中的可見view也要統(tǒng)計(jì),你可以根據(jù)newState去做區(qū)分
? ? ? ? ? ?SCROLL_STATE_IDLE:停止?jié)L動(dòng)
? ? ? ? ? ?SCROLL_STATE_DRAGGING: 用戶慢慢拖動(dòng)
? ? ? ? ? ?SCROLL_STATE_SETTLING:慣性滾動(dòng)
? ? ? ? ? ?*/
? ? ? ? ? ?if (newState == RecyclerView.SCROLL_STATE_IDLE) {
? ? ? ? ? ? ? ?.....
? ? ? ? ? ?}

? ? ? ?}

? ? ? ?@Override
? ? ? ?public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
? ? ? ? ? ?super.onScrolled(recyclerView, dx, dy);
? ? ? ? ? ........
? ? ? ?}
? ?});

首先再次明確下,我們要統(tǒng)計(jì)的是用戶停止滑動(dòng)時(shí),顯示在屏幕的上控件。所以我們要監(jiān)測(cè)到onScrollStateChanged 方法中
newState == RecyclerView.SCROLL_STATE_IDLE 時(shí),也就是用戶停止?jié)L動(dòng)。然后在這里做文章

三、獲取屏幕內(nèi)可見條目的起始位置

這里的起始位置就是指我們屏幕當(dāng)中最上面和最下面條目的位置。比如下圖的0就是最上面的可見條目,3就是最下面的可見條目。我們次數(shù)的曝光view就是0,1,2,3 這個(gè)時(shí)候這四個(gè)條目顯示在屏幕中。我們這時(shí)就要對(duì)這4個(gè)view的曝光量進(jìn)行加1
那么接下來的重點(diǎn)就是要去獲取屏幕內(nèi)可見條目的起始位置。獲取到起始位置后,當(dāng)前屏幕里的可見條目就都能拿到了。
而recylerview的manager正好給我們提供的有對(duì)應(yīng)的方法。
findFirstVisibleItemPosition()和findLastVisibleItemPosition() 看字面意思就能知道這時(shí)干嘛用的。
但是我們的manager不止LinearLayoutManager一種,所以我們要做下區(qū)分

//這里我們用一個(gè)數(shù)組來記錄起始位置
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獲取起始位置有點(diǎn)復(fù)雜,如下

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;
}

四、獲取到起始位置以后,我們就根據(jù)位置獲取到view及view中的數(shù)據(jù)

上面第三步拿到屏幕內(nèi)可見條目的起始位置以后,我們就用一個(gè)for循環(huán),獲取當(dāng)前屏幕內(nèi)可見的所有子view

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

recordViewCount是我自己寫的用于獲取子view內(nèi)綁定數(shù)據(jù)的方法

//獲取view綁定的數(shù)據(jù)
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綁定的數(shù)據(jù),相應(yīng)的你要去在你的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 + "----出現(xiàn)次數(shù):" + hashMap.get(key));
}

這里有幾點(diǎn)需要注意

這這里起始位置的view顯示區(qū)域如果不超過50%,就不算這個(gè)view可見,進(jìn)而也就不統(tǒng)計(jì)曝光。
我們通過view.getTag();獲取view里的數(shù)據(jù),必須在此之前setTag()數(shù)據(jù),我這里setTag是在viewholder中把數(shù)據(jù)set進(jìn)去的

到這里我們就實(shí)現(xiàn)了recylerview列表中view控件曝光量的統(tǒng)計(jì)了。下面貼出來完整的代碼給大家

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: 安卓曝光量統(tǒng)計(jì)工具類
?* wechat:2501902696
?*/
public class ViewShowCountUtils {

? ? //剛進(jìn)入列表時(shí)統(tǒng)計(jì)當(dāng)前屏幕可見views
? ? private boolean isFirstVisible = true;

? ? //用于統(tǒng)計(jì)曝光量的map
? ? private ConcurrentHashMap<String, Integer> hashMap = new ConcurrentHashMap<String, Integer>();


? ? /*
? ? ?* 統(tǒng)計(jì)RecyclerView里當(dāng)前屏幕可見子view的曝光量
? ? ?*
? ? ?* */
? ? void recordViewShowCount(RecyclerView recyclerView) {
? ? ? ? hashMap.clear();
? ? ? ? if (recyclerView == null || recyclerView.getVisibility() != View.VISIBLE) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //檢測(cè)recylerview的滾動(dòng)事件
? ? ? ? recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
? ? ? ? ? ? ? ? /*
? ? ? ? ? ? ? ? 我這里通過的是停止?jié)L動(dòng)后屏幕上可見view。如果滾動(dòng)過程中的可見view也要統(tǒng)計(jì),你可以根據(jù)newState去做區(qū)分
? ? ? ? ? ? ? ? SCROLL_STATE_IDLE:停止?jié)L動(dòng)
? ? ? ? ? ? ? ? SCROLL_STATE_DRAGGING: 用戶慢慢拖動(dòng)
? ? ? ? ? ? ? ? SCROLL_STATE_SETTLING:慣性滾動(dòng)
? ? ? ? ? ? ? ? */
? ? ? ? ? ? ? ? if (newState == RecyclerView.SCROLL_STATE_IDLE) {
? ? ? ? ? ? ? ? ? ? getVisibleViews(recyclerView);
? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? ? ? @Override
? ? ? ? ? ? public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
? ? ? ? ? ? ? ? super.onScrolled(recyclerView, dx, dy);
? ? ? ? ? ? ? ? //剛進(jìn)入列表時(shí)統(tǒng)計(jì)當(dāng)前屏幕可見views
? ? ? ? ? ? ? ? if (isFirstVisible) {
? ? ? ? ? ? ? ? ? ? getVisibleViews(recyclerView);
? ? ? ? ? ? ? ? ? ? isFirstVisible = false;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? });

? ? }

? ? /*
? ? ?* 獲取當(dāng)前屏幕上可見的view
? ? ?* */
? ? private void getVisibleViews(RecyclerView reView) {
? ? ? ? if (reView == null || reView.getVisibility() != View.VISIBLE ||
? ? ? ? ? ? ? ? !reView.isShown() || !reView.getGlobalVisibleRect(new Rect())) {
? ? ? ? ? ? return;
? ? ? ? }
? ? ? ? //保險(xiǎn)起見,為了不讓統(tǒng)計(jì)影響正常業(yè)務(wù),這里做下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", "屏幕內(nèi)可見條目的起始位置:" + 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綁定的數(shù)據(jù)
? ? 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綁定的數(shù)據(jù),相應(yīng)的你要去在你的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 + "----出現(xiàn)次數(shù):" + 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;
? ? }
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Android中點(diǎn)擊事件的幾種實(shí)現(xiàn)方式

    詳解Android中點(diǎn)擊事件的幾種實(shí)現(xiàn)方式

    本篇文章主要介紹了Android中點(diǎn)擊事件的實(shí)現(xiàn)方式,點(diǎn)擊事件的實(shí)現(xiàn)分為3中,詳細(xì)的介紹了三種的用法,有興趣的可以了解一下。
    2016-12-12
  • Android日期選擇器實(shí)現(xiàn)年月日三級(jí)聯(lián)動(dòng)

    Android日期選擇器實(shí)現(xiàn)年月日三級(jí)聯(lián)動(dòng)

    這篇文章主要為大家詳細(xì)介紹了Android日期選擇器實(shí)現(xiàn)年月日三級(jí)聯(lián)動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • Android App開發(fā)的自動(dòng)化測(cè)試框架UI Automator使用教程

    Android App開發(fā)的自動(dòng)化測(cè)試框架UI Automator使用教程

    UI Automator為Android程序的UI開發(fā)提供了測(cè)試環(huán)境,這里我們就來看一下Android App開發(fā)的自動(dòng)化測(cè)試框架UI Automator使用教程,需要的朋友可以參考下
    2016-07-07
  • Android OpenGL入門之GLSurfaceView

    Android OpenGL入門之GLSurfaceView

    這篇文章主要介紹了OpenGL入門知識(shí),如何在Android中使用GLSurfaceView,如果對(duì)OpenGL感興趣的同學(xué),可以參考下
    2021-04-04
  • Android實(shí)現(xiàn)微信支付功能

    Android實(shí)現(xiàn)微信支付功能

    這篇文章主要介紹了Android實(shí)現(xiàn)微信支付功能,微信支付功能,幾乎成為很多APP付款的主要方式之一,本文講解Android APP微信支付功能開發(fā),感興趣的小伙伴們可以參考一下
    2016-02-02
  • Android自定義EditText實(shí)現(xiàn)淘寶登錄功能

    Android自定義EditText實(shí)現(xiàn)淘寶登錄功能

    這篇文章主要為大家詳細(xì)介紹了Android自定義EditText實(shí)現(xiàn)淘寶登錄功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android的分辨率和屏幕適配詳解

    Android的分辨率和屏幕適配詳解

    對(duì)于剛接觸Android的新人和剛走上Android技術(shù)崗位的開發(fā)者們來說,在熟悉了相關(guān)之后,在項(xiàng)目完成后,就會(huì)面臨著一個(gè)重大的挑戰(zhàn),那么就是屏幕適配的問題。當(dāng)然我們所說的屏幕適配指的是適配各種手機(jī)不同的分辨率。
    2016-09-09
  • Android自定義View畫圓功能

    Android自定義View畫圓功能

    這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)畫圓功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Android使用AlertDialog實(shí)現(xiàn)對(duì)話框

    Android使用AlertDialog實(shí)現(xiàn)對(duì)話框

    本文主要介紹了Android使用AlertDialog實(shí)現(xiàn)對(duì)話框的相關(guān)知識(shí),具有很好的參考價(jià)值。下面跟著小編一起來看下吧
    2017-03-03
  • 淺談Android Studio 4.1 更新內(nèi)容

    淺談Android Studio 4.1 更新內(nèi)容

    這篇文章主要介紹了淺談Android Studio 4.1 更新內(nèi)容,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10

最新評(píng)論

安顺市| 龙陵县| 南雄市| 桃源县| 隆德县| 玉门市| 鄯善县| 舒兰市| 河津市| 永登县| 康马县| 化州市| 耒阳市| 巴东县| 郓城县| 夹江县| 泰宁县| 嘉兴市| 建宁县| 漳平市| 仪征市| 临夏县| 德州市| 海城市| 保亭| 博乐市| 汉中市| 达孜县| 武冈市| 满城县| 瓮安县| 丰城市| 宜兰市| 绥宁县| 定西市| 娄烦县| 拉萨市| 临汾市| 永德县| 夏邑县| 江口县|