您的位置:首页 > 其它

横向滑动的广告(网格控件)

2016-11-21 21:21 309 查看
转载请标明出处:

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.GVPager
android: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" />

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/gvp"
android:layout_centerHorizontal="true"
android:orientation="horizontal">

<glh.gvpager.view.IndicatorView
android: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};

@Override
protected 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();
}

@Override
protected void onDestroy() {
mGVPager.stop();
super.onDestroy();
}

public class GridPagerAdapter extends BaseAdapter {

int mSize;

public GridPagerAdapter(int size) {
mSize = size;
}

@Override
public int getCount() {
return mSize;
}

@Override
public Object getItem(int position) {
return position;
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public 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.GVPager
android: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();
}

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
public 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;//内嵌的GridView

private class GridPagerAdapter extends PagerAdapter {

@Override
public int getCount() {
return mHGridViewList.size();
}

@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}

@Override
public 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());
}

@Override
public ListAdapter getAdapter() {
return adapter;
}

@Override
public 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);
}
}

@Override
public View getSelectedView() {
if (getChildCount() > 0) {
return getChildAt(0);
}
return null;
}

@Override
public void setSelection(int i) {

}

@Override
public int getPaddingLeft() {
return mPaddingLeft;
}

@Override
public int getPaddingRight() {
return mPaddingRight;
}

@Override
protected 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));
}

@Override
protected 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;
}

@Override
public int getCount() {
if (adapter.getCount() % size == 0 || page < adapter.getCount() / size) {
return size;
}
return adapter.getCount() % size;
}

@Override
public Object getItem(int i) {
return adapter.getItem(page * size + i);
}

@Override
public long getItemId(int i) {
return adapter.getItemId(page * size + i);
}

@Override
public 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中的个数为准,超过移除View
mHGridViewList.remove(page + 1);// 每次都移除page+1位置的GridView
continue;
}
}
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项目源码地址:点击【项目源码】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐