Android_ViewPager实现滚动广告

Posted 9编程小王子9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android_ViewPager实现滚动广告相关的知识,希望对你有一定的参考价值。

转载表明出处:http://blog.csdn.net/zcr317121966/article/details/52060481

    作为一个android的初学者,我决定将自己所学所积累的知识点,实现功能记录再我的博客中。一是为了自己能反复查看提高能力,二也是为了能找到志同道合的博友学习和讨论。本人资历尚浅,但希望能一直坚持发博文,记录自己的成长之路。

    今天记录的是android中的ViewPager控件,实现的效果是很多软件上都存在的广告滚动条,图片和文字数据是抓接口从网上获取。

    首先分析以下思路。主要有以下几个部分,1.首先是页面的布局,ViewPager应为最外层,里面嵌套的是图片,文字和小圆点。一般为图片在最上方占一大部分,文字再最左下角一小部分,而小圆点再最右下并排排列,一般图片有多少张,那么小圆点就有多少个,而且图片切换到对应地方,小圆点会有不同标识。会嵌套用到的RelativeLayout,LinearLayout,其中会用到的控件有textview和RadioGroup。2.网络下载部分,本文是通过为的地址解析JSON数据得到的结果,分析,之后得到图片下载资源,和文字信息,再对图片进行下载。主要通过异步任务AsyncTask下载,网络请求数据HTTPURLConnection,接口回调传输数据。3.ViewPager逻辑部分,设置适配器和监听器,PagerAdapter,OnPageChangeListener。要实现文字,图片,小圆点的配套,和自己切换图片(滚动),和能认为的拖拽和滑动广告图片效果。

    大致分析过后得出以下几个类:1:MyMainActivity类,主函数类,主要处理的是初始化,设置属性,监听器,适配器等,是主要的运行逻辑处理类。2:AsyncTaskOfJson类,继承自 AsyncTask类,异步任务类。用于网址中的数据下载解析操作得到文本数据和图片资源数据。3:DataBean类,数据存储类,解析的JSON数据对应的属性存储到类中的对象中。4:AsyncTaskOfBtimap类,继承自 AsyncTask,也是用于将得到的图片资源通过异步任务下载图片。5:HTTPURLUtils类,下载工具类,封装方法提供网络数据的下载。6:MyInterface接口,用于实现接口后对网络上下载数据的回调传输数据。

    分析完成我们直接来看代码,运行是用anroidstudio,基本都有注解详细说明:

    1.首先布局文件:activity_my_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.bane.main.MyMainActivity">

    <!--
    首先广告滚动栏的最上方是一个可以滚动滑动的任意图片
    然后下面内嵌再底部位置的左边是文字说明,右边是小原点显示出是第几张图片
    -->

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="240dp">
        </android.support.v4.view.ViewPager
            >

    <RelativeLayout
        android:id="@+id/relativelayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/viewpager"
        >

    <LinearLayout
        android:id="@+id/linear_buttom"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="#440000FF"
        >

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <TextView
                android:id="@+id/textview"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:textSize="25sp"
                android:layout_alignParentLeft="true"
                android:textColor="#FFFFFF"
                android:text=""
            />

            <RadioGroup
                android:id="@+id/radiogroup"
                android:orientation="horizontal"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                />

            </RelativeLayout>
        </LinearLayout>
    </RelativeLayout>
</RelativeLayout>


2:AsyncTaskOfJson类
package com.bane.asynctask_json;

import android.os.AsyncTask;
import android.util.Log;

import com.bane.bean.DataBean;
import com.bane.myinterface.MyInterface;
import com.bane.utils.HttpURLUtils;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Bane on 2016/7/27 0027.
 * 此异步任务是通过给的网址下载网络数据
 * 通过utils包中封装的工具类下载json数据
 * 并进行解析之后得到所需要的数据
 * 三个范型分别为给的网址类型string
 * 第二为更新进度条类型用不到时为Void
 * 第三为得到的数据集合类型返回给main函数
 */
public class AsyncTaskOfJson extends AsyncTask<String,Void,List<DataBean>> 

    //声明接口引用,用于接受实现类对象,并调用接口方法回调传值
    private MyInterface myInterface;

    //List集合用来存储DataBean对象,对象中存储的是解析出来的数据
    private List<DataBean> list = new ArrayList<>();

    //重载构造方法,将传过来的对象赋值给本地声明的引用
    public AsyncTaskOfJson(MyInterface myInterface)

        this.myInterface = myInterface;

    
    //线程开启前的准备工作
    @Override
    protected void onPreExecute() 
        super.onPreExecute();
    

    //重写的异步任务中的方法再子线程中进行访问网路以及下载操作
    @Override
    protected List<DataBean> doInBackground(String... params) 

        //通过封装的HttpURLUtils类,获取得到的json数据

        String jsonString = HttpURLUtils.getDataOfString(params[0]);
        Log.i("===", "=========jsonString"+jsonString);

        /*
        http://bz.budejie.com/?typeid=2&ver=3.4.3&no_cry=1&client=android&c=topic&a=list&topictype=2&size=10
        * json数据结构如下:
        * 
            code: "E00000000",
            msg: "操作成功。",
            data: 
                    TotalCount: 16,
                    Topic: [
                        
                        subject: "春分",
                        cover_path: "http://bzpic.spriteapp.cn/picture1/M00/12/B0/wKiFQ1ULzuOAMR0wAADGL6xKvsU460.jpg",
                        ,...
                    ]
                 
            
        只截取了片段部分进行解析,大致结构可以看清楚
        * */

        try 
            //将json数据通过json解析为一个对象
            JSONObject jsonObject =  new JSONObject(jsonString);

            //取出对象中的data对象
            JSONObject jsonObject2=  jsonObject.getJSONObject("data");

            //取出data对象中的Topic数组
            JSONArray jsonArray = jsonObject2.getJSONArray("Topic");

            //通过数组遍历依次取出每个数组中对象里面的subjec 和 cover_path的值
            for (int i = 0; i < jsonArray.length(); i++) 

                //取出对应下标的对象
                JSONObject obj = jsonArray.getJSONObject(i);

                    //取出对应对象中对应属性的值
                    String subject = obj.getString("subject");
                    String cover_path =obj.getString("cover_path");
                    //通过Log打印出解析得到的数据
                    Log.i("===", "=============subject"+subject);
                    Log.i("===", "=============cover_path"+cover_path);

                //通过有参的构造方法创建对象
                DataBean dataBean =new DataBean(subject,cover_path);

                //将有值的对象存入到list集合中
                list.add(dataBean);
            


         catch (JSONException e) 
            e.printStackTrace();
        
        //将得到的结果返回
        return list;
    

    @Override
    protected void onPostExecute(List<DataBean> result) 

        if(result!=null)

            //得到list集合不为空之后立即接口回调传值
            myInterface.getDataFromTask(result);
        

        super.onPostExecute(result);
    

    //一般用于更新进度条
    @Override
    protected void onProgressUpdate(Void... values) 
        super.onProgressUpdate(values);
    




3:DataBean类
package com.bane.bean;

/**
 * Created by Bane on 2016/7/27 0027.
 * 此类是一个存储数据的类
 * 用于存储json解析得到的数据用此类存储
 * 并将不同数据的不同对象存储到集合中
 * 类的属性是根据获取的数据而定
 * 从json数据中只需要获得两个字段subject和cover_path
 * 所以本类只需要定义这两个变量进行封装
 */
public class DataBean 

    private String subject;
    private String cover_path;

    public DataBean(String subject, String cover_path) 
        this.subject = subject;
        this.cover_path = cover_path;
    

    public String getSubject() 
        return subject;
    

    public void setSubject(String subject) 
        this.subject = subject;
    

    public String getCover_path() 
        return cover_path;
    

    public void setCover_path(String cover_path) 
        this.cover_path = cover_path;
    

    @Override
    public String toString() 
        return "DataBean" +
                "subject='" + subject + '\\'' +
                ", cover_path='" + cover_path + '\\'' +
                '';
    





4:AsyncTaskOfBtimap类
package com.bane.asynctask_bitmap;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import com.bane.utils.HttpURLUtils;

/**
 * Created by bane on 2016/7/27 0027.
 */
public class AsyncTaskOfBtimap extends AsyncTask<String, Void, byte[]> 

    private ImageView imageView;

    //重载构造方法用于接受传过来的imageView对象,以便于设置背景现在广告
    public AsyncTaskOfBtimap(ImageView imageView) 
        this.imageView = imageView;
    

    @Override
    protected void onPreExecute() 
        super.onPreExecute();
    

    @Override
    protected byte[] doInBackground(String... params) 

        //通过封装的HttpURLUtils类得到网络上图片的字节数组并返回

        return HttpURLUtils.getDataOfByte(params[0]);
    

    @Override
    protected void onPostExecute(byte[] result) 

        if(result !=null)

            //通过bitmap工厂将获取到的字节数组加工为一个bitmap对象
            Bitmap bitmap = BitmapFactory.decodeByteArray(result,0,result.length);

            //并将得到的bitmap对象设置为imageView的背景图片
            imageView.setImageBitmap(bitmap);
        

        super.onPostExecute(result);
    

    @Override
    protected void onProgressUpdate(Void... values) 
        super.onProgressUpdate(values);
    



5:HTTPURLUtils类
package com.bane.myinterface;

import com.bane.bean.DataBean;
import java.util.List;

/**
 * Created by Bane on 2016/7/27 0027.
 * 此接口用于AsyncTask异步任务下载时候接口回调传回数据
 */
public interface MyInterface 

    public abstract void getDataFromTask(List<DataBean> data);



6:MyInterface接口
package com.bane.myinterface;

import com.bane.bean.DataBean;
import java.util.List;

/**
 * Created by Bane on 2016/7/27 0027.
 * 此接口用于AsyncTask异步任务下载时候接口回调传回数据
 */
public interface MyInterface 

    public abstract void getDataFromTask(List<DataBean> data);



7:MyMainActivity类
package com.bane.main;


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.bane.asynctask_bitmap.AsyncTaskOfBtimap;
import com.bane.asynctask_json.AsyncTaskOfJson;
import com.bane.bean.DataBean;
import com.bane.myinterface.MyInterface;
import com.example.administrator.android22_viewpagerhorizontal.R;

import java.util.ArrayList;
import java.util.List;


public class MyMainActivity extends Activity 

    //mTextview用于显示栏目左下方的文字显示
    private TextView mTextview;

    //ViewPager滚动图片广告显示
    private ViewPager mViewpager;

    //RadioGroup右下小圆点显示
    private RadioGroup mRadiogroup;

    //viewpager自动滚动时的操作
    private Runnable r;

    //定义屏幕高度
    private int height_screen;

    //flag表示用于判断
    private boolean flag =false;

    //ViewPager适配器
    private PagerAdapter pAdapter;

    //handler用于发送消息执行某个操作
    private Handler handler = new Handler();

    //用于存储得到数据存储在对象中的集合
    private List<DataBean> list_data = new ArrayList<>();

    //用于存储imageview集合
    private List<ImageView> list_image = new ArrayList<>();

    //这是下载数据的网址
    private String path = "http://bz.budejie.com/?typeid=2&ver=3.4.3&no_cry=1&client=android&c=topic&a=list&topictype=2&size=10";

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_main);

        //打开异步任务开始下载数据
        startAsyncTask();

    

    private void init() 

        //初始化控件
        assignViews();

        //初始化imageview
        initIamgeView();

        //初始化radiobutton
        initRadioButton();

        //初始化适配器
        initPagerAdapter();

        //设置viewpager监听事件
        setViewPagerOnListener();

        //刷新适配器并设置适配器
        pAdapter.notifyDataSetChanged();
        mViewpager.setAdapter(pAdapter);

        //设置
        setPosition();

    

    private void startAsyncTask() 

        //首先开启异步任务下载数据
        //并在创建对象是传入一个匿名接口并实现接口方法用于接口回调获得数据
        new AsyncTaskOfJson(new MyInterface() 
            @Override
            public void getDataFromTask(List<DataBean> data) 

                //将传回的数据加到本类中的list_data集合中
                list_data.addAll(data);

                //log打印得到的数据的个数
                Log.i("===", "================list.size()" + list_data.size());

                //下载数据结束后再进行初始化操作让初始化的控件和下载的匹配
                init();

            
        ).execute(path);
    

    private void assignViews() 

        //初始化控件对象
        mViewpager = (ViewPager) findViewById(R.id.viewpager);
        mTextview = (TextView) findViewById(R.id.textview);
        mRadiogroup = (RadioGroup) findViewById(R.id.radiogroup);


        //通过方法获取屏幕的高度
        height_screen = getResources().getDisplayMetrics().heightPixels;

        //通过获取控件属性将viewpager高度改为屏幕高度的三分之一
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mViewpager.getLayoutParams();
        params.height = height_screen / 3;
        mViewpager.setLayoutParams(params);

    


    private void initIamgeView() 

        //先用循环将list_data中加入对应个数的imageview设置其属性
        for (int i = 0; i < list_data.size(); i++) 
            ImageView imageView = new ImageView(this);

            //设置tag标识
            imageView.setTag(i);

            //设置背景并当下载网络上数据之后进行更改
            imageView.setBackgroundResource(R.mipmap.ic_launcher);

            //设置宽高满屏拉伸
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);

            //将imageview对象加入到集合中
            list_image.add(imageView);

            //通过异步任务在网络下载图片,下载地址为list_data数据中的下标i对应对象
            //的cover_path属性值  为该图片的地址 下载完成之后会在异步任务中将下载好的
            //图片设为该对应下标的imageview上
            new AsyncTaskOfBtimap(imageView).execute(list_data.get(i).getCover_path());
        
    

    private void initRadioButton() 

        //通过for循环添加对应数量的radiobutton与之对应
        for (int i = 0; i < list_data.size(); i++) 
            RadioButton rb = new RadioButton(this);

            //设置id唯一标识
            rb.setId(i);

            //再drawable文件中设置的selector当被checked和非checked状态下的图标有所区别
            rb.setButtonDrawable(R.drawable.button_back);

            //设置radiobutton不可以点击的
            rb.setClickable(false);

            //将设置好的radiobutton add到radiogroup中
            mRadiogroup.addView(rb);
        
    

    private void initPagerAdapter() 

        //new一个viewpager适配器
        pAdapter = new PagerAdapter() 

            @Override
            public int getCount() 

                //适配器大小,如果list_image中有数据则返回int中最大值(以便后期的左右侧滑范围)
                //事实上的效果是用户在滑动的图片中不是饶了一个圈从第最后一张又滑到了第一张
                //而是很多个图片循环的显示在viewpager中所以返回的个数不能为本身图片的个数
                //而是一个大的数字,先且设置为int最大值,下面起始位置也是一个道理,设置为2000

                return list_image==null? 0: Integer.MAX_VALUE;

//                return  4000;

            

            //判断是否有缓存,通常写法如下
            @Override
            public boolean isViewFromObject(View view, Object object) 

                return view == object;
            

            //提前通过list下表取出image并add到ViewGroup中,position最大为int最大值
            //所以需要取余于当前的总个数得到的下表再取得其中的imageview对象(去下标部分都需要取余)
            @Override
            public Object instantiateItem(ViewGroup container, int position) 

                container.addView(list_image.get(position % list_image.size()));


                return list_image.get(position % list_image.size());
            

            //销毁暂时不会用到的image,释放资源,由于viewpager只会加载到当前下表先后各一个的页面
            //总共三个页面,其他的都会被销毁
            @Override
            public void destroyItem(ViewGroup container, int position, Object object) 

                container.removeView(list_image.get(position % list_image.size()));
//                super.destroyItem(container, position, object);
            
        ;
    

    //设置viewpager监听事件
    private void setViewPagerOnListener() 
        mViewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() 

            //左右拖拽时的下标,比例和距离
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 

            

            //当此项被选中时
            @Override
            public void onPageSelected(int position) 

                //通过mRadiogroup对象的getChildAt方法出去对应下标的radiobutton对象并getId
                //再通过check方法设定为checked状态与图片的下标对应显示
                mRadiogroup.check(mRadiogroup.getChildAt(position % list_data.size()).getId());

                //同理取出对应下标中对象中的subject属性,是对应的图片的描述文字,setText到textview中
                mTextview.setText(list_data.get(position % list_data.size()).getSubject());
            

            //监听状态
            @Override
            public void onPageScrollStateChanged(int state) 

                switch (state) 
                    //停止滑动
                    //当停止滑动后 用handler开启一个r继续运行切换图片功能
                    //但是当用户图片自动切换是每停止3秒的时间时也会调用一次handler,
                    //会重复无数次的调用切换图片操作所以引入了一个flag值作为标记
                    //当flag为true时可以正常运行一次后,置为false仅此有一个r再运作


                    case ViewPager.SCROLL_STATE_IDLE:
                            if(flag)
                                handler.postDelayed(r,3000);
                                flag=false;
                            
                        break;

                    //正在滑动
                    //正在滑动的时候不能切换图片所以将r移除
                    //滑动停止后将flag置为true
                    //上述监听又可以进行判断执行一次r进程来切换图片
                    case ViewPager.SCROLL_STATE_DRAGGING:

                        handler.removeCallbacks(r);
                        flag=true;

                        break;

                    case ViewPager.SCROLL_STATE_SETTLING:

                        break;

                    default:
                        break;
                
            
        );
    

    private void setPosition() 

        //r进程是每隔三秒会自动向右切换一张图片。

        //由于防止用户最开始会向坐滑动所以将起始的下标设为2000
        //如果起始下标为0则一开始无法向左滑动
        mViewpager.setCurrentItem(2000);

        r = new Runnable() 
            @Override
            public void run() 
                //延时3秒调用一次本进程,类似于自己调用自己(递归)
                //会重复无限次的调用下去
                handler.postDelayed(this,3000);

                //通过viewpager对象setCurrentItem和getCurrentItem方法
                //得到的下标加1设置为新下标则实现了图片的切换效果
                mViewpager.setCurrentItem(mViewpager.getCurrentItem()+1);
            
        ;

        //启动图片切换效果
        handler.postDelayed(r,3000);
    



8:清单配置文件需要加上权限
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.administrator.android22_viewpagerhorizontal">


    <!-- 添加网络访问的权限-->
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">

        </activity>
        <activity android:name="com.bane.main.MyMainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



9:drawable中的button_back背景选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 将导入的两张图片分别设置为radiobutton选中和不选中的时候的图片以便于美观-->

    <item android:drawable="@mipmap/abc_btn_radio_to_on_mtrl_000" android:state_checked="false"/>
    <item android:drawable="@mipmap/abc_btn_radio_to_on_mtrl_015" android:state_checked="true"/>

</selector>


10:实现效果如下









以上是关于Android_ViewPager实现滚动广告的主要内容,如果未能解决你的问题,请参考以下文章

iOScollectionView广告无限滚动(Swift实现)

JQuery实现广告效果(滚动切换)

高仿京东APP首页“京东快报”自动向上滚动的广告条

原生JS实现各种经典网页特效——Banner图滚动选项卡切换广告弹窗等

原生JS实现各种经典网页特效——Banner图滚动选项卡切换广告弹窗等

自定义View--单行上下滚动广告