亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

實(shí)現(xiàn)輪轉(zhuǎn)廣告帶底部指示的自定義ViewPager控件

 更新時(shí)間:2013年11月21日 16:56:58   作者:  
在項(xiàng)目中經(jīng)常需要使用輪轉(zhuǎn)廣告的效果,在android-v4版本中提供的ViewPager是一個(gè)很好的工具,而一般我們使用Viewpager的時(shí)候,都會(huì)選擇在底部有一排指示物指示當(dāng)前顯示的是哪一個(gè)page,下面我們就做這個(gè)功能的實(shí)現(xiàn)

有許多博客和開(kāi)源項(xiàng)目都致力于這項(xiàng)工作,但是他們的工作大都是為了制作類似于啟動(dòng)頁(yè)的效果,ViewPager全屏顯示,或者自己可操作的屬性難以滿足要求,因此我想把ViewPager和底部的指示物封裝在一個(gè)自定義的View中,作為一個(gè)新的控件在xml中使用,所以自己來(lái)實(shí)現(xiàn)了一個(gè)。
而且,在用自定義視圖封裝ViewPager時(shí),出現(xiàn)了一個(gè)問(wèn)題,就是ViewPager的所有頁(yè)不能全部顯示的問(wèn)題,不知道是因?yàn)檫@個(gè)問(wèn)題太簡(jiǎn)單還是什么其它原因,在網(wǎng)上并沒(méi)有搜到這個(gè)問(wèn)題的解決方法(事實(shí)上連提問(wèn)的人都沒(méi)有……),困擾了我半個(gè)多星期,終于解決,這一點(diǎn)在正文里會(huì)介紹,先來(lái)貼一下效果圖:

下面來(lái)介紹我的實(shí)現(xiàn)過(guò)程:

首先在res/values/目錄下創(chuàng)建attrs.xml文件,用來(lái)定義新View自定義的屬性:

復(fù)制代碼 代碼如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyViewPager">
        <attr name="dotsViewHeight" format="dimension" />
        <attr name="dotsSpacing" format="dimension" />
        <attr name="dotsFocusImage" format="reference" />
        <attr name="dotsBlurImage" format="reference" />
        <attr name="android:scaleType" />
        <attr name="android:gravity" />
        <attr name="dotsBackground" format="reference|color" />
        <attr name="dotsBgAlpha" format="float" />
        <attr name="changeInterval" format="integer" />
    </declare-styleable>
</resources>

其中:

dotsViewHeight定義底部指示物所在視圖(我定義為一個(gè)LinearLayout)的高度,也就是示例圖中圓圈所在灰色透明部分的高度,默認(rèn)為40像素;

dotsSpacing定義底部指示物之間的間距,默認(rèn)為0;

dotsFocusImage定義代表當(dāng)前頁(yè)的指示物的樣子;

dotsBlurImage定義代表非當(dāng)前頁(yè)的指示物的樣子;

android:scaleType定義ViewPager中ImageView的scale類型,如果ViewPager中的View不是ImageView,則此屬性沒(méi)有效果,默認(rèn)為ScaleType.FIT_XY;

android:gravity定義底部指示物在父View(即示例灰色透明部分)的gravity屬性;

dotsBackground定義底部指示物的背景顏色或背景圖;

dotsBgAlpha定義底部指示物的背景顏色或背景圖的透明度,取值為0-1,0代表透明;

changeInteval定義ViewPager自動(dòng)切換的時(shí)間間隔,單位為ms,默認(rèn)為1000ms(這個(gè)地方實(shí)際的間隔比設(shè)置的要大,不知道是什么原因,望高手解答);

下一步,定義PageAdapter,為ViewPager提供內(nèi)容:

復(fù)制代碼 代碼如下:

public class ViewPagerAdapter extends PagerAdapter {

    private List<View> views = null;
    private ScaleType scaleType;

    public ViewPagerAdapter(List<View> views) {
        this(views, ScaleType.CENTER);
    }

    public ViewPagerAdapter(List<View> views, ScaleType scaleType) {
        super();
        this.views = views;
        this.scaleType = scaleType;
    }

定義一個(gè)views來(lái)存儲(chǔ)要顯示的View,然后定義一個(gè)ScaleType來(lái)規(guī)定如果ViewPager是用來(lái)顯示ImageView的,ImageView應(yīng)該怎樣呈現(xiàn)在ViewPager當(dāng)中,如果調(diào)用的構(gòu)造函數(shù)不傳ScaleType信息,則默認(rèn)使用ScaleType.CENTER。
根據(jù)官方API描述,需要重寫(xiě)PageAdapter的getCount,isViewFromObject,instantiateItem和destroyItem這四個(gè)方法,在instantiateItem中設(shè)置ScaleType,其它幾個(gè)方法,都是用官方描述的寫(xiě)法,沒(méi)有做什么新的改動(dòng):

復(fù)制代碼 代碼如下:

@Override
public int getCount() {
    // TODO Auto-generated method stub
    return views.size();
}

@Override
public boolean isViewFromObject(View arg0, Object arg1) {
    // TODO Auto-generated method stub
    return arg0 == arg1;
}

@Override
public Object instantiateItem(View container, int position) {
    // TODO Auto-generated method stub
    View view = views.get(position);
    ViewPager viewPager = (ViewPager) container;
    if (view instanceof ImageView){
        ((ImageView) view).setScaleType(scaleType);
    }
    viewPager.addView(view, 0);
    return view;
}

@Override
public void destroyItem(View container, int position, Object object) {
    // TODO Auto-generated method stub
    ((ViewPager) container).removeView((View) object);
}

下面就是重頭戲了,核心類,被封裝的底部帶指示物的ViewPager,基本思路是自定義一個(gè)類繼承LinearLayout,在里面加入兩個(gè)子視圖ViewPager和LinearLayout(放置指示物),并且,因?yàn)橐ㄆ谳嗈D(zhuǎn),還實(shí)現(xiàn)了Runnable接口,定義了以下的變量:

復(fù)制代碼 代碼如下:

public class MyViewPager extends LinearLayout implements Runnable {

    private ViewPager viewPager;
    private LinearLayout viewDots;
    private List<ImageView> dots;
    private List<View> views;

    private int position = 0;
    private boolean isContinue = true;

    private float dotsViewHeight;
    private float dotsSpacing;
    private Drawable dotsFocusImage;
    private Drawable dotsBlurImage;
    private ScaleType scaleType;
    private int gravity;
    private Drawable dotsBackground;
    private float dotsBgAlpha;
    private int changeInterval;

viewPager是要顯示的ViewPager對(duì)象,viewDots是放置指示物的子視圖,dots是viewDots上的指示物項(xiàng),views是ViewPager項(xiàng),position指示當(dāng)前正在顯示第幾張圖,isContinue表示可不可以自動(dòng)輪轉(zhuǎn)(當(dāng)手指觸摸時(shí)不輪轉(zhuǎn)),在下面的就是雨attrs.xml中定義的屬性相對(duì)應(yīng)的值。作為一個(gè)能夠在xml布局文件中直接使用的View,必須重寫(xiě)擁有Context和AttributeSet參數(shù)的構(gòu)造函數(shù):

復(fù)制代碼 代碼如下:

public MyViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
    // TODO Auto-generated constructor stub
    TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.MyViewPager, 0, 0);

try {
        dotsViewHeight = a.getDimension(
                    R.styleable.MyViewPager_dotsViewHeight, 40);
            //這里依次獲取所有的屬性值,此處省略,可參看最后附上的全部代碼
        } finally {
            a.recycle();
        }

    initView();
}

最后調(diào)用的函數(shù)initView,用來(lái)初始化ViewPager和LinearLayout這兩個(gè)子視圖,同時(shí),如果xml中給指示物設(shè)置了背景,在這里進(jìn)行設(shè)置:

復(fù)制代碼 代碼如下:

@SuppressLint("NewApi")
private void initView() {
    // TODO Auto-generated method stub
    viewPager = new ViewPager(getContext());
    viewDots = new LinearLayout(getContext());

    LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
            LayoutParams.MATCH_PARENT);
    addView(viewPager, lp);
    if (dotsBackground != null) {
        dotsBackground.setAlpha((int) (dotsBgAlpha * 255));
        viewDots.setBackground(dotsBackground);
    }
    viewDots.setGravity(gravity);
    addView(viewDots, lp);
}


使用這個(gè)類時(shí),關(guān)鍵就是創(chuàng)建一個(gè)List<View>,并作為參數(shù)傳進(jìn)來(lái)供ViewPager(PagerAdapter)使用,對(duì)外的接口就是這個(gè)setViewPagerViews:

復(fù)制代碼 代碼如下:

public void setViewPagerViews(List<View> views) {
    this.views = views;
    addDots(views.size());

    viewPager.setAdapter(new ViewPagerAdapter(views, scaleType));

    viewPager.setOnPageChangeListener(new OnPageChangeListener() {
        @Override
        public void onPageSelected(int index) {
            // TODO Auto-generated method stub
            position = index;
            switchToDot(index);
        }
        //override的兩個(gè)空方法,此處省略
    });

    viewPager.setOnTouchListener(new OnTouchListener() {

        @Override
        public boolean onTouch(View view, MotionEvent motionevent) {
            // TODO Auto-generated method stub
            switch (motionevent.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                isContinue = false;
                break;
            case MotionEvent.ACTION_UP:
                isContinue = true;
                break;
            default:
                isContinue = true;
                break;
            }
            return false;
        }
    });
    new Thread(this).start();
}

addDots就是在底部添加多少個(gè)小點(diǎn),默認(rèn)第一個(gè)處于被選中狀態(tài),關(guān)鍵是OnPageChangeListener的onPageSelected方法,這個(gè)方法在viewPager進(jìn)行切換時(shí)調(diào)用,做的工作就是把底部的指示物切換到對(duì)應(yīng)的標(biāo)識(shí)上,在這個(gè)方法的最后,啟動(dòng)了輪轉(zhuǎn)的線程。

復(fù)制代碼 代碼如下:

@Override
public void run() {
    // TODO Auto-generated method stub
    while (true) {
        if (isContinue) {
            pageHandler.sendEmptyMessage(position);
            position = (position + 1) % views.size();
            try {
                Thread.sleep(changeInterval);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Handler pageHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        // TODO Auto-generated method stub
        viewPager.setCurrentItem(msg.what);
        super.handleMessage(msg);
    }
};

在這個(gè)線程中,每隔固定秒數(shù),就向Handler隊(duì)列中發(fā)送一個(gè)消息,內(nèi)容就是要顯示的view項(xiàng)的index,然后再handler中調(diào)用viewPager的setCurrentItem方法進(jìn)行跳轉(zhuǎn)。至此,最核心的類就完成了,但還剩很關(guān)鍵的一個(gè)方法,作為一個(gè)自定義的View,要重寫(xiě)父類的onLayout方法來(lái)對(duì)子元素進(jìn)行布局,就是這一個(gè)方法中不當(dāng)?shù)拇a,導(dǎo)致每次只能顯示前兩張圖,因?yàn)閂iewPager在顯示時(shí),會(huì)默認(rèn)初始化當(dāng)前頁(yè)和前后頁(yè),對(duì)于第一張來(lái)說(shuō),沒(méi)有前一頁(yè),所以初始化了兩張,在ViewPager滑動(dòng)時(shí),每次都會(huì)調(diào)用onLayout方法,而且,changed參數(shù)為false,我已開(kāi)始只判斷changed為true時(shí)才進(jìn)行布局,就造成了上述問(wèn)題,完整的onLayout代碼如下:

復(fù)制代碼 代碼如下:

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    // TODO Auto-generated method stub
    View child = this.getChildAt(0);
    child.layout(0, 0, getWidth(), getHeight());

    if (changed) {
        child = this.getChildAt(1);
        child.measure(r - l, (int) dotsViewHeight);
        child.layout(0, getHeight() - (int) dotsViewHeight, getWidth(),
                getHeight());
    }
}

最后,就是如何使用這個(gè)類了,首先,在activity的布局文件中聲明這個(gè)組件:

復(fù)制代碼 代碼如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:daemon="http://schemas.android.com/apk/res/org.daemon.viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#666666" >

    <org.daemon.viewpager.MyViewPager
        android:id="@+id/my_view_pager"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        daemon:dotsViewHeight="30dp"
        daemon:dotsFocusImage="@drawable/dot_focused"
        daemon:dotsBlurImage="@drawable/dot_normal"
        daemon:dotsSpacing="5dp"
        daemon:dotsBackground="#999999"
        daemon:dotsBgAlpha="0.5"
        daemon:changeInterval="3000"
        android:scaleType="fitXY"
        android:gravity="center" />

</RelativeLayout>

然后,在MainActivity中,創(chuàng)建List<View>數(shù)組并設(shè)置數(shù)據(jù):

復(fù)制代碼 代碼如下:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initViewPager();
}

private void initViewPager() {
    views = new ArrayList<View>();

    ImageView image = new ImageView(this);
    image.setImageResource(R.drawable.demo_scroll_image);
    views.add(image);
    image = new ImageView(this);
    image.setImageResource(R.drawable.demo_scroll_image2);
    views.add(image);
    image = new ImageView(this);
    image.setImageResource(R.drawable.demo_coupon_image);
    views.add(image);
    image = new ImageView(this);
    image.setImageResource(R.drawable.demo_scroll_image2);
    views.add(image);

    MyViewPager pager = (MyViewPager) findViewById(R.id.my_view_pager);
    pager.setViewPagerViews(views);
}

至此,本示例就全部講解完了,兩個(gè)問(wèn)題,一個(gè)就是為什么使用Thread的方法來(lái)控制時(shí)間間隔,實(shí)際值會(huì)比設(shè)置的值長(zhǎng),是因?yàn)镸essage在排隊(duì)嗎,第二個(gè)問(wèn)題,就是為什么ViewPager滑動(dòng)時(shí)不重新對(duì)ViewPager布局,就會(huì)不顯示任何圖,這兩個(gè)問(wèn)題還有待大家解答。

相關(guān)文章

  • Android短信備份及數(shù)據(jù)插入實(shí)現(xiàn)代碼解析

    Android短信備份及數(shù)據(jù)插入實(shí)現(xiàn)代碼解析

    這篇文章主要介紹了Android短信備份及數(shù)據(jù)插入實(shí)現(xiàn)代碼解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Android圖片加載框架Coil的詳細(xì)使用總結(jié)

    Android圖片加載框架Coil的詳細(xì)使用總結(jié)

    Coil是Android上的一個(gè)全新的圖片加載框架,它的全名叫做coroutine image loader,即協(xié)程圖片加載庫(kù),下面這篇文章主要給大家介紹了關(guān)于Android圖片加載框架Coil詳細(xì)使用的相關(guān)資料,需要的朋友可以參考下
    2022-07-07
  • Android路由框架ARouter的使用示例

    Android路由框架ARouter的使用示例

    組件化或者模塊化開(kāi)發(fā)模式,已逐漸成為熱浪的形式,使用這些模式可以讓我們程序更容易的擴(kuò)展、更方便的維護(hù)、更快捷的同步開(kāi)發(fā)與更簡(jiǎn)單的單獨(dú)調(diào)試,而ARouter的出現(xiàn)就是讓組件間、模塊間是實(shí)現(xiàn)完全的獨(dú)立。ARouter主要解決組件間、模塊間的界面跳轉(zhuǎn)問(wèn)題。
    2021-06-06
  • ReactNative (API)AsyncStorage存儲(chǔ)詳解及實(shí)例

    ReactNative (API)AsyncStorage存儲(chǔ)詳解及實(shí)例

    這篇文章主要介紹了ReactNative (API)AsyncStorage存儲(chǔ)詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • Android中切換到主線程執(zhí)行的方法

    Android中切換到主線程執(zhí)行的方法

    這篇文章主要介紹了Android中切換到主線程執(zhí)行的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Android實(shí)現(xiàn)雷達(dá)View效果的示例代碼

    Android實(shí)現(xiàn)雷達(dá)View效果的示例代碼

    這篇文章主要介紹了Android實(shí)現(xiàn)雷達(dá)View效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Android 數(shù)據(jù)庫(kù)SQLite 寫(xiě)入SD卡的方法

    Android 數(shù)據(jù)庫(kù)SQLite 寫(xiě)入SD卡的方法

    如果手機(jī)沒(méi)有root,數(shù)據(jù)庫(kù)文件是無(wú)法查看到的,不方便調(diào)試。最好的辦法是把數(shù)據(jù)庫(kù)寫(xiě)進(jìn)SD卡。通過(guò)本文給大家介紹Android 數(shù)據(jù)庫(kù)SQLite 寫(xiě)入SD卡的方法,需要的朋友參考下吧
    2016-04-04
  • Android Studio打包APK文件具體實(shí)現(xiàn)步驟解析

    Android Studio打包APK文件具體實(shí)現(xiàn)步驟解析

    這篇文章主要介紹了Android Studio打包APK文件具體實(shí)現(xiàn)步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Android實(shí)現(xiàn)去哪兒攜程地址互換效果

    Android實(shí)現(xiàn)去哪兒攜程地址互換效果

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)去哪兒攜程地址互換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Android中l(wèi)istview和imageview實(shí)現(xiàn)條目單選效果

    Android中l(wèi)istview和imageview實(shí)現(xiàn)條目單選效果

    這篇文章主要為大家詳細(xì)介紹了Android中l(wèi)istview和imageview實(shí)現(xiàn)條目單選效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-02-02

最新評(píng)論