如何让Android的adView始终显示在ListView最后一项下方?
问题解答
当前布局能否实现需求?
不能。当前activity_results里的ListView和adView被放在独立的ConstraintLayout中,而这个ConstraintLayout与ViewPager同级且都设置了match_parent高度,会直接覆盖ViewPager;而content_results是ViewPager对应页面的列表项布局,两者完全没有关联,自然无法让adView跟随ListView最后一项的底部。
你尝试的app:layout_constraintBottom_toTopOf无效,是因为ListView高度设为wrap_content,且整体布局层级错误,约束没有在正确的上下文生效。
布局中的基础错误
- 冗余嵌套:最外层的
RelativeLayout完全多余,内部直接是CoordinatorLayout,没有用到任何RelativeLayout的属性,徒增布局层级。 - 布局重叠:
ViewPager和ConstraintLayout都设置了match_parent高度,且都添加了app:layout_behavior="@string/appbar_scrolling_view_behavior",导致两者重叠,ConstraintLayout会覆盖ViewPager,使得ViewPager的页面无法正常显示。 - 属性混用无效:
adView中使用了android:layout_alignParentBottom="true"(这是RelativeLayout的属性),但它的父布局是ConstraintLayout,该属性完全无效。 - 属性不规范:
content_results.xml中使用的fill_parent可替换为match_parent,fill_parent是旧API写法,match_parent更符合当前Android开发规范。
正确实现adView跟随ListView最后一项底部的方法
推荐两种可行方案:
方案1:将adView作为ListView的最后一项(推荐)
在ListView的Adapter中,把广告项作为列表的最后一条数据:
- 创建广告项布局(比如
item_ad.xml),内容就是AdView。 - 在Adapter的
getCount()方法中,返回原数据数量+1。 - 在
getView()方法中,判断当前position是否为最后一项,若是则加载广告布局,否则加载正常的content_results布局。
示例Adapter核心代码(ListView版本):
@Override public int getCount() { return originalData.size() + 1; // 原数据数量+1条广告 } @Override public View getView(int position, View convertView, ViewGroup parent) { if (position == originalData.size()) { // 加载广告布局 if (convertView == null) { convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_ad, parent, false); AdView adView = convertView.findViewById(R.id.adView); // 初始化广告加载 AdRequest adRequest = new AdRequest.Builder().build(); adView.loadAd(adRequest); } return convertView; } else { // 加载正常列表项布局 if (convertView == null || !(convertView.getTag() instanceof NormalViewHolder)) { convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.content_results, parent, false); NormalViewHolder holder = new NormalViewHolder(convertView); convertView.setTag(holder); } NormalViewHolder holder = (NormalViewHolder) convertView.getTag(); // 绑定数据 YourData data = originalData.get(position); holder.abc.setText(data.getAbc()); holder.def.setText(data.getDef()); holder.ghi.setText(data.getGhi()); return convertView; } } static class NormalViewHolder { TextView abc; TextView def; TextView ghi; NormalViewHolder(View itemView) { abc = itemView.findViewById(R.id.abc); def = itemView.findViewById(R.id.def); ghi = itemView.findViewById(R.id.ghi); } }
方案2:用LinearLayout包裹ListView和adView(适合数据量少的场景)
如果ListView数据量不大,可将两者放在垂直方向的LinearLayout中,给ListView设置android:layout_weight="1"让其占满剩余空间,adView固定在底部:
<!-- 此布局放在ViewPager对应的Fragment中 --> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <com.google.android.gms.ads.AdView android:id="@+id/adView" android:layout_width="match_parent" android:layout_height="wrap_content" ads:adSize="SMART_BANNER" ads:adUnitId="@string/banner_ad_unit_id"/> </LinearLayout>
注意:这种方式下,滚动ListView时adView会固定在屏幕底部,而非跟随最后一项下方被带出屏幕;如果需要adView在列表最后一项的下方,方案1更合适。
修正后的activity_results布局
去掉冗余的RelativeLayout和错误的ConstraintLayout,保留正确的CoordinatorLayout结构:
<?xml version="1.0" encoding="utf-8"?> <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:ads="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.test.test.ResultsActivity"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" app:titleTextAppearance="@style/ToolbarTitle" /> <com.google.android.material.tabs.TabLayout android:id="@+id/tabs" android:layout_width="match_parent" android:layout_height="wrap_content" app:tabMaxWidth="0dp"> <com.google.android.material.tabs.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/tab_text_1" /> <com.google.android.material.tabs.TabItem android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/tab_text_2" /> </com.google.android.material.tabs.TabLayout> </com.google.android.material.appbar.AppBarLayout> <androidx.viewpager.widget.ViewPager android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
内容的提问来源于stack exchange,提问作者Zac1
相关产品推荐
相关产品推荐

