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

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://glhcode.blog.csdn.net/article/details/53264494

转载请标明出处:
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项目源码地址:[点击【项目源码】](https://github.com/LinhaiGu/GVPagerProject)
展开阅读全文

没有更多推荐了,返回首页