如何在listView中的每个第n个位置显示AdView

时间:2014-02-27 20:07:38

标签: android listview

我有下面的代码,除了它总是隐藏列表视图中的至少一个真实项目,因为广告显示在该位置。

问题示例:我有4次列表,adView显示在列表视图的第3位我只能看到3次和AdView,第4项没有得到显示

我每次返回广告时都会增加适配器的大小,但效果并不好。

有什么想法吗?

public View getView(final int position, View row, ViewGroup parent) {
        MyHolder holder = null;
        boolean showAd = proVersion == false && (position % 8 == k);
        if (showAd) {
            AdView adView = adList.get(position);
            if (adView == null) {
                AdView adViewNew = new AdView((Activity) context, AdSize.BANNER, context.getResources().getString(
                        R.string.adId));
                adViewNew.loadAd(Utils.getAdRequest("gps", lat, lng, keywords));
                adList.add(position, adViewNew);
                return adViewNew;
            } else {
                return adView;
            }
        } else if (row == null || row instanceof AdView) {
            LayoutInflater inflater = ((SherlockActivity) context).getLayoutInflater();
            row = inflater.inflate(viewResourceId, parent, false);
            holder = new MyHolder();
            holder.textName = (TextView) row.findViewById(R.id.name);           
            row.setTag(holder);
        } else {
            holder = (MyHolder) row.getTag();
        }
        holder.textName.setText(items.get(position).getName());

        // more code

        return row;
    }

    @Override
    public int getCount() {
        if (items != null) {
            return items.size();
        } else {
            return 0;
        }
    }

8 个答案:

答案 0 :(得分:6)

实现这一目标的方法不止一种。最好的方法是依靠listView的能力来回收多种项目类型。

在你的适配器中,

  1. getViewTypeCount() - 返回listView
  2. 中有多少行类型的信息
  3. getItemViewType(int position)根据位置返回应使用哪种布局类型的信息。这就是你确定listView对象的逻辑应该去的地方。
  4. 有一个关于如何使用different item types in a list here的好教程: 具体来说,请查看“不同列表项”布局。

    之后,您需要对索引进行少量算术转换,以便将位置映射到数据结构中的正确位置(或者,您可以合并数据结构以包含广告数据和项目数据)。

    基本上,您需要使用items.size()+ Math.floor(items.size()/ NTH_ITEM)而不是使用items.size(),当您获得该位置时,如果它是广告位置(位置%) NTH_ITEM == 0)使用像Math.floor(position / NTH_ITEM)这样的简单转换从广告数据结构中提取,并以类似的方式提取项目的结构。

    您应该依赖ListView的holder模式来重用您的不同项视图类型,就像上面的教程一样。

    不同的方法,仅用于概念,包括使用类似于将数据源合并为一个的项包装器,并通过使用类型属性(如枚举)或合并两个特定适配器的“合并适配器”来区分项目(如果要将这些视图类型包含在不同的列表中,这可能具有更好的模块性。)

    如果您在使用案例中需要任何帮助来实现特定部分,请告诉我。

答案 1 :(得分:3)

Ben Max的回答更清晰。 建议在处理不同类型的视图时使用视图类型。

这是一个很好的方法。

为您的不同数据类型创建一个包装器:

private class ItemWrapper {
               public static final int TYPE_NORMAL = 0;
               public static final int TYPE_AD = 1;
               public static final int TYPE_COUNT = 2; 

                public ListObject item;
                public AdObject adItem;
                public int type;

                public ItemWrapper(ListObject item) {
                    this.type = TYPE_NORMAL;
                    this.item = item
                }
                public ItemWrapper(AdObject adItem) {
                    this.type = TYPE_AD;
                    this.adItem = adItem;  
                }
}

现在对适配器进行一些更改:

假设您在构造函数中初始化适配器

 public class MyAdapter extends BaseAdapter{
    ArrayList<ItemWrapper> mWrappedItems = new ArrayList<ItemWrapper>();
         public void MyAdapter(List<ListObject> items,AdItem adItem){

                for(ListObject item:items){
                    mWrappedItems.add(new ItemWrapper(item));
                }
                //you can insert your ad item wherever you want!
                mWrappedItems.add(2,new ItemWrapper(adItem)); 

            }
}

然后对适配器进行一些更改:

@Override
   public ItemWrapper getItem(int position) {
      return mWrappedItems == null ? null : mWrappedItems.get(position);
   }
   @Override
    public int getItemViewType(int position) {
        return getItem(position).type;
    }

    @Override
    public int getViewTypeCount() {
        //tells the adapter how many different view types it will need to recycle
        return ItemWrapper.TYPE_COUNT;
    }

现在为你的getView .... 你会发现这更好,因为你可以控制你的观点被夸大的方式

public View getView(final int position, View row, ViewGroup parent) {
        final ItemWrapper item = getItem(position);
        final int type = item.type;
        if (row == null) {
            if (type == ItemWrapper.TYPE_NORMAL) {
                //inflate your normal view layouts
            } else if (type == ItemWrapper.TYPE_AD) {
                //inflate your ad layout
            }
        }

        //now you can easily populate your views based on the type
        if (type == ItemWrapper.TYPE_NORMAL) {
            //get your item data
            final ListObject data = item.item;
            //populate as you would normally
        } else if (type == ItemWrapper.TYPE_AD) {
            final AdItem adItem = item.adItem;
            //populate your ad as needed
        }
        return row;
    }

您会注意到,通过操作列表而不是在getView()中执行任何奇怪的逻辑,您可以很好地控制项目的显示方式/位置。它还使您可以轻松地根据类型扩展布局并轻松填充它们。 我希望这有帮助! P.S我之前也写了一篇关于这个主题的博客文章: http://qtcstation.com/2012/04/a-limitation-with-the-viewholder-pattern-on-listview-adapters/

答案 2 :(得分:1)

我会采用不同的方式,而不是动态添加广告布局。假设您的布局(通过View row方法的getView()参数访问)是自定义的,只需在其中添加LinearLayout,该AdView将用于<LinearLayout ...> <!-- Put here the AdView layout --> <LinearLayout android:id="@+id/adViewLL" ... android:visibility="gone" /> <!-- Add whatever else you need in your default layout --> ... </LinearLayout> 。< / p>

由于您不希望它在所有行上都可见,因此默认情况下标记其可见性已经消失,但以这种方式定义它将允许您控制布局并定义它应如何显示。

假设这是你的布局文件:

getView()

现在只需更改您的VISIBLE方法,即可在{14}}时将展示次数设置为View,并为AdView添加public View getView(final int position, View row, ViewGroup parent) { MyHolder holder = null; boolean showAd = proVersion == false && (position % 8 == k); if (row == null) { LayoutInflater inflater = ((SherlockActivity) context).getLayoutInflater(); row = inflater.inflate(viewResourceId, parent, false); holder = new MyHolder(); holder.textName = (TextView) row.findViewById(R.id.name); row.setTag(holder); if (showAd) { LinearLayout myAd = (LinearLayout) row.findViewByid(R.id.adViewLL); myAd.setVisibility(View.VISIBLE); AdView adViewNew = new AdView((Activity) context, AdSize.BANNER, context.getResources().getString(R.string.adId)); ... myAd.addView(adViewNew); } } else { holder = (MyHolder) row.getTag(); } holder.textName.setText(items.get(position).getName()); // more code return row; }

{{1}}

答案 3 :(得分:0)

我会在nKn的回答中添加以下经验:

  1. 使用ViewSwitcher
  2. 封装广告视图
  3. 显示广告所在的消息,例如:“来自我们可爱赞助商的消息......”
  4. 当广告回调击中你(onAdLoaded)时,请执行holder.switcher.setDisplayedChild(1); // if 1 is where your AdView is.
  5. 有一个标记,您可以在其中停用广告,以便始终如果(showAd&amp;&amp; adsEnabled){},您永远不知道何时可能需要停用广告,如果您有API尝试从那里检索该值。
  6. #4也可用于else子句:else {holder.switcher.setDisplayedChild(0);//your generic message}
  7. 有一个“AdController”,您可以在其中确定频道(每个##项目要插入广告)。并让您的列表询问if (YourAdController.isAd(position) && adsEnabled) { do the add thing }

答案 4 :(得分:0)

这是一个逻辑错误。

以下是对发生的事情的解释。

根据您的说明,每8次展位都是广告

为什么继续搞乱视图或维护多个布局

在您的数据集中(即您传递给适配器的列表),只需在每个 8x 位置添加一个表示广告项的项目

因此,如果是专业版,则列表中没有广告项条目

最后,在你的getview中

if(ad item)
    populate adView
else
    populate regularItemView

希望它简化

答案 5 :(得分:0)

我在其中一个应用程序上遇到了同样的问题。这是与我合作的方法。

  • 首先,您需要创建一个包含广告详细信息的类。

    公共类AdUnitDetails {     private String mUnitId;     private int mIndex;

    public AdUnitDetails(String mUnitId,int mIndex) {
        super();
        this.mUnitId = mUnitId;
        this.mIndex = mIndex;
    }
    
    public String getUnitId() {
        return mUnitId;
    }
    
    public void setUnitId(String mUnitId) {
        this.mUnitId = mUnitId;
    }
    
    
    public int getIndex() {
        return mIndex;
    }
    
    public void setIndex(int mIndex) {
        this.mIndex = mIndex;
    }
    

    }

  • 然后,您创建一个包含其位置

    的广告的Sparsearray
    SparseArray<AdView> mAdViewsMap = new SparseArray<AdView>();
    
  • 然后,您需要修改适配器以接收对象的arraylist,然后在填写此列表时将广告添加到相应的位置。示例(项目,项目,项目,addetails,项目,项目等)。

  • 然后,在您的适配器中。添加以下方法:

    private static final int TYPE_ITEM= 0;
    private static final int TYPE_AD = 1;
    private static final int TYPES_COUNT = TYPE_AD + 1;
    
    @Override
    public int getViewTypeCount() {
        return TYPES_COUNT;
    }
    
    @Override
    public int getItemViewType(int position) {
        if (mItems.get(position) instanceof YourItemClass)
            return TYPE_ITEM;
        else if (mItems.get(position) instanceof AdUnitDetails)
            return TYPE_AD;
    return super.getItemViewType(position);
    }
    
  • 然后,在您的getView()方法中,添加以下内容

        View view = convertView;
        if (mItems.get(position) instanceof YourItemClass) {
            // Handle your listview item view
        } else if (mItems.get(position) instanceof AdUnitDetails) {
            return getAdView(position);
        }
    
        return view;
    
  • 您的getAdView()方法

     private AdView getAdView(final int position) {
    if (mAdViewsMap.get(position) == null) {
        AdSize adSize = getAdSize(AdSize.BANNER);
        AdView mAdView = new AdView(mContext, adSize, ((AdUnitDetails) mItems.get(position)).getUnitId());
        mAdView.loadAd(new AdRequest());
        mAdViewsMap.put(position, mAdView);
        return mAdView;
    } else {
        return mAdViewsMap.get(position);
    }
    

    }

答案 6 :(得分:0)

可能为时已晚,但这就是我如何解决我的问题。 将当前位置从int转换为string(可选) 然后每次视图膨胀时检查位置是否包含(3 || 6 || 9),因为每个第3个可见布局都显示广告横幅。希望它有用,如果需要,将发布代码:)  哦和||意味着&#34;或&#34;如果有人想知道

答案 7 :(得分:0)

这里是代码Ashish Kumar Gupta

RelativeLayout rl = (RelativeLayout) convertView.findViewById(R.id.adviewlayout); //putting the advertisement banner inside a relativelayout/linearlayout if you want. so that you can make it visibile whenever you want.

    String pos = String.valueOf(position); // converting listview item position from int to string//


    if (pos.endsWith("3")||pos.endsWith("6")||pos.endsWith("9")) {
        // every fourth position will show an advertisement banner inside a listview. here is the proof (0,1,2,advertisement,4,5,advertisement,7,8,advertisement,10,11,12,advertisement,14,15,advertisement,17,18,advertisement,20). did not put advertisements in 0 position cuz its rude to put advertisements in like the first layout in my POV//

        rl.setVisibility(View.VISIBLE);

    }
    else 
    {
        rl.setVisibility(View.GONE);

//如果不是第3个位置的广告将不会显示//         }         欢迎你:)