转载请标明出处:
http://blog.csdn.net/hai_qing_xu_kong/article/details/53264494
本文出自:【顾林海的博客】

##前言
很早以前写过一篇自定义广告控件的文章,这篇文章也是自定义广告控件,不同的是内部包含的是列表,具体看效果图:

##使用方式

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/darker_gray"><glh.gvpager.view.GVPagerandroid:id="@+id/gvp"android:layout_width="match_parent"android:layout_height="100dp"android:padding="5dp"app:columnMargin="10dp"app:columnNumber="2"app:rowMargin="10dp"app:rowNumber="1" /><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_below="@id/gvp"android:layout_centerHorizontal="true"android:orientation="horizontal"><glh.gvpager.view.IndicatorViewandroid:id="@+id/indicator"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout></RelativeLayout>
package glh.gvpager;import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.util.Random;import glh.gvpager.view.GVPager;
import glh.gvpager.view.IndicatorView;public class MainActivity extends AppCompatActivity {private IndicatorView indicator;private GVPager mGVPager;private int[] resourceId = {R.drawable.demo1, R.drawable.demo2, R.drawable.demo3, R.drawable.demo4,R.drawable.demo5, R.drawable.demo6, R.drawable.demo1, R.drawable.demo2,R.drawable.demo3, R.drawable.demo1};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);GridPagerAdapter gridPagerAdapter = new GridPagerAdapter(10);mGVPager = (GVPager) findViewById(R.id.gvp);indicator = (IndicatorView) findViewById(R.id.indicator);mGVPager.setIndicator(indicator);mGVPager.setAutoDuration(500);mGVPager.setPageTransformer(new CubeTransformer());mGVPager.setAdapter(gridPagerAdapter);mGVPager.play();}@Overrideprotected void onDestroy() {mGVPager.stop();super.onDestroy();}public class GridPagerAdapter extends BaseAdapter {int mSize;public GridPagerAdapter(int size) {mSize = size;}@Overridepublic int getCount() {return mSize;}@Overridepublic Object getItem(int position) {return position;}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if (convertView == null) {viewHolder = new ViewHolder();convertView = getLayoutInflater().inflate(R.layout.item_gvp, null);viewHolder.iv_demo = (ImageView) convertView.findViewById(R.id.iv_demo);convertView.setTag(viewHolder);} else {viewHolder = (ViewHolder) convertView.getTag();}viewHolder.iv_demo.setImageResource(resourceId[position]);return convertView;}}static class ViewHolder {ImageView iv_demo;}
}

##原理说明

左右滑动视图的最好方案非ViewPager莫属,因此创建一个继承ViewPager的类,并且定义一些属性:

gv_attrs:

<resources><declare-styleable name="GridViewPager"><attr name="columnNumber" format="integer" />//列数<attr name="rowNumber" format="integer" />//行数<attr name="columnMargin" format="dimension" />//列间距<attr name="rowMargin" format="dimension" />//行间距<attr name="android:paddingLeft" /><attr name="android:paddingRight" /><attr name="android:padding" /></declare-styleable></resources>

在activity_main中的使用 :

<glh.gvpager.view.GVPagerandroid:id="@+id/gvp"android:layout_width="match_parent"android:layout_height="300dp"android:padding="5dp"app:columnMargin="10dp"app:columnNumber="2"app:rowMargin="10dp"app:rowNumber="1" />

OK,目前我们是想创建一个一行两列,行间距和列间距都是10dp,四周间距是5dp的GVPager控件,创建GVPager类。

public class GVPager extends ViewPager {private static final int DEFAULT_COLUMN_NUMBER = 2;private static final int DEFAULT_ROW_NUMBER = 3;private int mRowNumber = DEFAULT_ROW_NUMBER;// 行private int mColumnNumber = DEFAULT_COLUMN_NUMBER;// 列private float mColumnMargin = 0;//列间距private float mRowMargin = 0;//行间距private int mPaddingLeft = 0;//左边距private int mPaddingRight = 0;//右边距public GVPager(Context context) {this(context, null);}public GVPager(Context context, AttributeSet attrs) {super(context, attrs);getAttributeSet(attrs);}/*** 获取设置的属性值** @param _attrs AttributeSet*/private void getAttributeSet(AttributeSet _attrs) {if (_attrs != null) {TypedArray typedArray = getContext().obtainStyledAttributes(_attrs, R.styleable.GridViewPager);int count = typedArray.getIndexCount();for (int i = 0; i < count; i++) {int attr = typedArray.getIndex(i);switch (attr) {case R.styleable.GridViewPager_columnNumber:mColumnNumber = typedArray.getInt(attr, -1);break;case R.styleable.GridViewPager_rowNumber:mRowNumber = typedArray.getInt(attr, -1);break;case R.styleable.GridViewPager_columnMargin:mColumnMargin = typedArray.getDimension(attr, 0);break;case R.styleable.GridViewPager_rowMargin:mRowMargin = typedArray.getDimension(attr, 0);break;case R.styleable.GridViewPager_android_padding:int padding = typedArray.getDimensionPixelSize(attr, 0);setPadding(padding, padding, padding, padding);break;case R.styleable.GridViewPager_android_paddingLeft:mPaddingLeft = typedArray.getDimensionPixelSize(attr, 0);break;case R.styleable.GridViewPager_android_paddingRight:mPaddingRight = typedArray.getDimensionPixelSize(attr, 0);break;default:break;}}typedArray.recycle();}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overridepublic void setPadding(int left, int top, int right, int bottom) {mPaddingLeft = left;mPaddingRight = right;super.setPadding(0, top, 0, bottom);}}

GVPager类继承自ViewPager,上面的代码是获取自定义的属性值,这里面重写了setPadding方法,并手动将左右边距设置0,这是为什么呢?因为我们设置的是ViewPager内部View的左右边距,而不是设置ViewPager的左右间距。

接着给ViewPager设置相应的PagerAdapter,ViewPager显示的每一个Item View都是一个HGridView,效果图可以看出ItemView实际上是类似与GridView一样,是以列表形式展示的,ViewPager的每一个View都是一个AdapterView,也就是这里的HGridView是一个继承自AdapterView的类。

GVPager适配器:

private List<HGridView> mHGridViewList = null;//内嵌的GridViewprivate class GridPagerAdapter extends PagerAdapter {@Overridepublic int getCount() {return mHGridViewList.size();}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View) object);}@Overridepublic Object instantiateItem(ViewGroup container, int position) {container.addView(mHGridViewList.get(position), new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));return mHGridViewList.get(position);}
}

HGridView继承自AdapterView, 而AdapterView继承自ViewGroup,因此,还得实现onMeasure和onLayout方法,用于子View的测量和定位:

public class HGridView extends AdapterView<ListAdapter> {private ListAdapter adapter;public HGridView() {super(GVPager.this.getContext());}@Overridepublic ListAdapter getAdapter() {return adapter;}@Overridepublic void setAdapter(ListAdapter listAdapter) {this.adapter = listAdapter;int oldChildCount = getChildCount();int newChildCount = adapter.getCount();int deleteChildCount = oldChildCount - newChildCount;for (int i = oldChildCount; i < newChildCount; i++) {View child = adapter.getView(i, null, this);addViewInLayout(child, i, new LayoutParams(0, 0));}if (deleteChildCount > 0) {removeViewsInLayout(newChildCount, deleteChildCount);}}@Overridepublic View getSelectedView() {if (getChildCount() > 0) {return getChildAt(0);}return null;}@Overridepublic void setSelection(int i) {}@Overridepublic int getPaddingLeft() {return mPaddingLeft;}@Overridepublic int getPaddingRight() {return mPaddingRight;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {/*获取子View宽高*/int width = (int) ((MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight() - mColumnMargin * (mColumnNumber - 1)) / mColumnNumber);int height = (int) ((MeasureSpec.getSize(heightMeasureSpec) - mRowMargin * (mRowNumber - 1)) / mRowNumber);int count = getChildCount();for (int i = 0; i < count; i++) {View child = getChildAt(i);/*给子View设置宽高*/LayoutParams layoutParams = child.getLayoutParams();layoutParams.width = width;layoutParams.height = height;child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));}setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {int childCount = getChildCount();int childLeft = 0;int childTop = 0;for (int i = 0; i < childCount && i < mRowNumber * mColumnNumber; i++) {View child = getChildAt(i);int x = i % mColumnNumber;if (x == 0) {/*每一行的第一个子View*/childLeft = getPaddingLeft();}LayoutParams layoutParams = child.getLayoutParams();child.layout(childLeft, childTop, childLeft + layoutParams.width, childTop + layoutParams.height);childLeft += layoutParams.width + mColumnMargin;if (x == mColumnNumber - 1) {/*每一行最后一个子View,要另起一行*/childTop += layoutParams.height + mRowMargin;}}}
}

setAdapter方法主要做了以下几件事:

  • 填充adapter中的View。
  • 如果该AdapterView之前的子View数量大于新添加的子View数,需要移除多余的View。

填充完每屏的子View后,就需要我们测量子View的大小,实现onMeasure方法,子View的宽高我们可以根据下图分析,剩下做的就是给子View定位。具体看一下代码,相信大家都能看懂。 :

由上图可以计算出子View的宽高:

宽=(AdapterView_Width-paddingLeft-paddingRight-(列Margin)*(列数-1))/列数

高=(AdapterView_Height-(行Margin)*(行数-1))/行数

既然HGridView定义完毕,接着就得给我们的AdapterView绑定适配器,适配器所要做的事情就是定义ViewPager中每一个HGridView显示多少个View以及所要显示的View:

private class GridAdapter extends BaseAdapter {private int page;private int size;private BaseAdapter adapter;public GridAdapter(int _page, int _size, BaseAdapter _adapter) {this.size = _size;this.page = _page;this.adapter = _adapter;}@Overridepublic int getCount() {if (adapter.getCount() % size == 0 || page < adapter.getCount() / size) {return size;}return adapter.getCount() % size;}@Overridepublic Object getItem(int i) {return adapter.getItem(page * size + i);}@Overridepublic long getItemId(int i) {return adapter.getItemId(page * size + i);}@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {return adapter.getView(page * size + i, view, viewGroup);}
}

GVPager和HGridView已经定义完毕,接下来所做的事情就是给他们绑定适配器 :

private void resetAdapter() {// 行*列=当前屏的总个数int pageSize = mColumnNumber * mRowNumber;if (pageSize <= 0)return;if (mAdapter.getCount() == 0) {mHGridViewList.removeAll(mHGridViewList);}int pageCount = mAdapter.getCount() / pageSize;int listSize = mHGridViewList.size() - 1;HGridView hGridView;GridAdapter gridAdapter;for (int i = 0, page = (mAdapter.getCount() % pageSize == 0) ? pageCount-- : pageCount; i <= Math.max(listSize, page); i++) {if (i <= listSize && i <= page) {// 更新hGridView = mHGridViewList.get(i);gridAdapter = new GridAdapter(i, pageSize, mAdapter);hGridView.setAdapter(gridAdapter);mHGridViewList.set(i, hGridView);continue;}if (i > listSize && i <= page) {// 添加hGridView = new HGridView();gridAdapter = new GridAdapter(i, pageSize, mAdapter);hGridView.setAdapter(gridAdapter);mHGridViewList.add(hGridView);continue;}if (i > page && i <= listSize) {// 以设置的Adapter中的个数为准,超过移除ViewmHGridViewList.remove(page + 1);// 每次都移除page+1位置的GridViewcontinue;}}super.setAdapter(new GridPagerAdapter());if (mSelection >= 0) {setSelection(mSelection);}
}

到这里横向滚动的网格广告已经定义完毕,剩下的自动滚动和动画就不介绍了,下面给出这个控件的一些公共方法:

设置ViewPager的Adapter
public void setAdapter(BaseAdapter _adapter)
刷新
public void notifyDataSetChanged()
定位位置
public void setSelection(int position)
获取总页数
public int getPageCount()
获取总个数
public int getPageSize()
设置指示器
public void setIndicator(IndicatorView _indicator)
自动切换开启.
public void play()
停止播放
public void stop()
设置ViewPager的切换动画
public void setPageTransformer(PageTransformer _pageTransformer)
滑动速度
public void setAutoDuration(int _duration) 

##项目下载地址
> 以下是完整的github项目地址,欢迎多多star和fork。 > github项目源码地址:[点击【项目源码】](https://github.com/LinhaiGu/GVPagerProject)

Android之横向滑动的广告(网格控件)相关推荐

  1. java使用gridview,网格控件GridView在Android中的使用

    我们在上面之前发表过一篇"使用Gallery实现缩略图浏览器",今天介绍另一种类似的控件,但是该控件是以网格的方式显示的,也就是说,当我们使用它来显示一组图片,结果图片将会以类似九 ...

  2. Android横向滚动卡片,Android实现横向滑动卡片效果

    Android实现横向滑动卡片效果 发布时间:2020-09-04 22:51:17 来源:脚本之家 阅读:255 作者:itbobby 最近项目上需要实现这样效果的一个页面,本来想找个现成的两下搞定 ...

  3. android 固定底部 布局_Android系统列表控件

    在android系统控件中,有多个控件可以展示列表数据. 一.ListView 该组件是android中最常用的一个UI组件,用于实现在屏幕上显示多个内容,以便于我们用手指进行滑动. ListView ...

  4. android listview添加数据_Android系统列表控件

    在android系统控件中,有多个控件可以展示列表数据. 一.ListView 该组件是android中最常用的一个UI组件,用于实现在屏幕上显示多个内容,以便于我们用手指进行滑动. ListView ...

  5. 【Android】App首页上下滚动快报控件 通知控件 类似京东快报控件(一)

    前言 快过年了,对于大伙来说手头上的事情做完没有呢,马上也该让自己轻松一阵子了,哈哈哈.好,说正事,由于公司App这个版本首页的改版,新增了很多新的控件,类似于京东快报这种控件的话我在写之前也去找了一 ...

  6. ExtJs学习笔记(4)_EditorGridPanel(可编辑的网格控件)

    这一节,我们将看到ExtJs功能强大的可编辑网格控件,几乎与VS.Net的GridView功能一样了,但是ExtJs的可是纯JS的UI 一.静态示例(改自ExtJs的官方示例) a.因为我们是采用xm ...

  7. 移动界面控件Essential Studio for Mobile MVC网格控件解析

    移动界面控件Essential Studio for Mobile MVC是Syncfusion公司旗下一款企业级的用于移动应用开发的界面控件,整个套包中包含了grids.charts.gauges. ...

  8. android富文本图片自适应,Android 图片混排富文本编辑器控件

    一.一个Android 图片混排富文本编辑器控件(仿兴趣部落) 1.1 图片混排富文本控件 是一种图片和文字混合在一起的控件,文本之间可以插入图片,类似于网页的排版样式. 1.2 该控件主要是仿兴趣部 ...

  9. wxWidgets:网格控件 wxWidgets 示例

    wxWidgets:网格控件 wxWidgets 示例 wxWidgets:网格控件 wxWidgets 示例 griddemo.h griddemo.cpp wxWidgets:网格控件 wxWid ...

最新文章

  1. 今天是第一次开博客,for--futurechild!!!
  2. Science:便携式DNA测序仪在检测病毒疫情中大显身手
  3. 企业融入租时代 谋求轻资产化高效运营
  4. 我发现养生这个梗好像在程序员圈火起来了
  5. elasticsearch-jdbc实现MySQL同步到ElasticSearch深入详解
  6. Day2 HTML基本标签元素
  7. linux网络编程之多路I/O转接服务器poll函数
  8. 函数式编程在Redux/React中的应用
  9. 免费申请 Office365 E5 开发者订阅
  10. jQuery中的read 和JavaScript中 的onload函数的区别
  11. 关于全局低级键盘hook的记录(WH_KEYBOARD_LL)
  12. HTML5基础语法详述
  13. SharePoint中CAML日期格式
  14. 分享个自己Python爬虫时的浏览器标识库
  15. 如何在柿饼派中用mqtt接收数据并进行解析
  16. UT-Exynos4412 三星ARM四核旗舰开发平台android4.0体验-5联通3G功能调试支持
  17. Python30 网络编程通讯协议,1.学习网络编程的目的 2.什么是互联网 3.c/s结构 4.通讯基本要素 5.OSI模型...
  18. 有一个整数,加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?完全平方数:16=4*4
  19. iPhone 11依然坚挺的原因是什么?
  20. 友盟的常见使用----三方登陆、分享和“埋点”(友盟统计)

热门文章

  1. mysql 错误1930xc1_Mysql写入记录出现 Incorrect string value: '\xB4\xE7\xB1\xCA\xBC\xC7‘错误?(写入中文)...
  2. groovy 使用java类_在java中使用groovy怎么搞 (java and groovy)
  3. flutter git 拉不起来_「干货」Flutter开发环境配置备忘录
  4. (原創) 將map輸出到cout,是否有更方便的方法? (C/C++) (STL)
  5. 程序清单3.3_bases.c程序_《C Primer Plus》P37
  6. MySql数据库概念
  7. Commonly Hacked Ports
  8. Java中读取某个目录下的所有文件和文件夹
  9. 解决NGUI中sprite的边缘会出现黑线的问题
  10. 微软私有云分享(R2)7-Linux虚拟机无DNS?