老豬帶你玩轉android自定義控件一——打造最簡單viewpagerindicator

  viewpagerindicator,既使用viewpager翻頁時候,標題的指示條隨着改變的控件,是經常使用android控件之一,幾乎全部的新聞類APP中都有使用。以下圖所示:android

  今天,咱們將從0到1實現這一控件。ide

  其實,實現這一控件思路很簡單:佈局

  ①對頭部的標題欄進行佈局,頭部標題欄,只能進行單選,這符合radiobutton的特質,可是普通的radiobutton,不是這樣的嗎?動畫

      

  顯然,咱們在這裏須要寫樣式進行處理,因爲頭部標題欄的條目很是的多,一個屏幕放不下,所以咱們須要一個水平滾動條來盛放這不少的條目。this

  ②咱們看到底部的內容隨着指示條再不斷滑動,所以底部內容是一個viewpager。spa

  ③下面就是這個控件最關鍵的部分,就是指示條隨着viewpager的內容相互滾動,這涉及到必定邏輯,下面我會闡述這方面的邏輯內容。3d

  說了一大段開場白之後,咱們就應該庖丁解牛般的實現咱們控件,廢話少說,直接上代碼,首先,粉墨登場是頭部控件xml佈局文件。code

  

<!-- 
  頭部標題欄 
 包含一個水平滾動條
 單選按鈕組
 以及一個標題指示條
 -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    
    <HorizontalScrollView
        android:id="@+id/hsv"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:fadingEdge="none"
        android:scrollbars="none" >

        <!-- 單選按鈕 -->

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

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

            <FrameLayout
                android:layout_width="fill_parent"
                android:layout_height="2dp" >

                <View
                    android:id="@+id/indicator"
                    android:layout_width="100dp"
                    android:layout_height="2dp"
                    android:background="#ff0000" />
            </FrameLayout>
        </LinearLayout>
    </HorizontalScrollView>

</LinearLayout>

  咱們看到這個控件包含一個可以左右滾動水平滾動條,因爲每一個標題條目就是一個radiobutton,因此須要把這個radio button 放在一個單項按鈕組中。固然,還須要一個指示翻到第幾頁的指示條。xml

  接下來,就是重頭戲了,這個自定義控件邏輯控制。咱們看一下他的流程圖對象

  

  經過上述流程圖,咱們能夠得出指示條伴隨頭部欄與viewpager滑動而滑動。

  作了這麼多鋪墊,這個控件的核心——邏輯代碼將要暴露他的廬山真面目。

  一個自定義控件,首先要初始化原有控件。代碼以下:

  

    /**
     * 初始化 相應控件 而且爲相應控件賦予相應的事件
     * @param context
     */
    @SuppressLint("InflateParams")
    private void initView(Context context) {

        hsv = (HorizontalScrollView) findViewById(R.id.hsv);

        rg = (RadioGroup) findViewById(R.id.rg);
        rg.setOnCheckedChangeListener(this);
        indicator = findViewById(R.id.indicator);

    }

    /**
     * 爲標題條目動態賦值
     */
    public void setDatas(List<String> datas) {
        this.datas = datas;
        addView();
    }

    /**
     * 將標題控件動態添加radiobuttonGroup控件中去
     */
    @SuppressLint("ResourceAsColor")
    private void addView() {
        for (int i = 0; i < datas.size(); i++) {
            RadioButton radioButton = new RadioButton(getContext());
            radioButton.setText(datas.get(i));
            radioButton.setId(10000 + i);
            radioButton.setBackgroundResource(R.color.white);
            radioButton.setButtonDrawable(null);
            radioButton.setButtonDrawable(android.R.color.transparent);
            radioButton.setTextColor(R.color.black);
            LayoutParams layoutParams = new LayoutParams(Dp2Px(getContext(),
                    100), LayoutParams.WRAP_CONTENT);
            radioButton.setLayoutParams(layoutParams);
            radioButton.setGravity(Gravity.CENTER);
            int px = Dp2Px(getContext(), 8);
            radioButton.setPadding(px, px, px, px);

            rg.addView(radioButton);
        }
        
    }
    

  這裏,大夥應當對兩個方面的問題引發重視:

  ①咱們所說哪些頭部標題並非固定的,是動態生成的,所以顯示每一個標題radiobutton控件,是隨着標題的條目動態添加到父控件中去的。

  ②前文說道,因爲每一個radiobutton樣式很是醜陋,不符合咱們的需求,所以咱們須要經過相應的代碼控制它的樣式。

  因爲這個控件歸根結底是對viewpager翻頁效果進行一個指示,怎麼可以少得了viewpager對象,相應的源代碼以下:

    /**
     * 設置viewpager對象
     */
    public void setPager(ViewPager pager) {
        this.pager = pager;
        setPagerListener();
    }

    /**
     * 對viewpager翻頁進行監聽
     */
    private void setPagerListener() {
        pager.setOnPageChangeListener(this);
    }    

  其主要就是對於viewpager的翻頁效果進行監聽。

  怎麼使翻頁翻到那一頁的時候,指示條也隨之移動,讓我媽老瞅瞅他的代碼:

    /**
     * 頁面滾動 指示條隨之移動 當條目滾出屏幕的時候,水平滾動條也隨之移動
     */
    @Override
    public void onPageScrolled(int position, float positionOffset,
            int positionOffsetPixels) {
        int sum = 0;
        sum = (int) ((position+positionOffset)*rg.getChildAt(position).getWidth());
        
        int green = (pager.getWidth() - rg.getChildAt(position).getWidth()) / 2;
        dx = sum - green;// 計算出要滑出去的距離
        hsv.scrollTo(dx, 0);
        tempx=hsv.getScrollX();
        indicatorScroll(position, positionOffset);

    }

    /**
     * 指示條隨着頁面的移動也跟隨着滑動
     */
    int tempx=0;
    private void indicatorScroll(int position, float positionOffset) {
        RadioButton button = (RadioButton) rg.getChildAt(position);
        int[] location = new int[2];
        button.getLocationInWindow(location);
        // 開始作位移滑動
        TranslateAnimation animation = new TranslateAnimation(fromX,
                location[0] + positionOffset * button.getWidth()+tempx, 0, 0);
        animation.setDuration(50);// 動畫持續事件
        animation.setFillAfter(true);
        fromX = (int) (location[0] + button.getWidth() * positionOffset+tempx);
        indicator.startAnimation(animation);// 線開始動畫
    }    

  對於這個邏輯,你們應當注意兩點:

  第一點,單條目滾出屏幕的時候,咱們應當相應條目將其滾動到屏幕中央位置,那麼他所需滾動位置,如圖所示:

 

 第二點,關於指示條計算就是移動到相應條目位置-水平滾動條滾動的位置。

  這樣一個自定義的viewpagerindicator就大功告成了,效果以下:

  

  源代碼地址爲:

  http://pan.baidu.com/s/1eQ9Fi62

相關文章
相關標籤/搜索