zoukankan      html  css  js  c++  java
  • 老猪带你玩转android自定义控件一——打造最简单viewpagerindicator

      viewpagerindicator,既使用viewpager翻页时候,标题的指示条随着改变的控件,是常用android控件之一,几乎所有的新闻类APP中都有使用。如下图所示:

      今天,我们将从0到1实现这一控件。

      其实,实现这一控件思路很简单:

      ①对头部的标题栏进行布局,头部标题栏,只能进行单选,这符合radiobutton的特质,但是普通的radiobutton,不是这样的吗?

          

      显然,我们在这里需要写样式进行处理,由于头部标题栏的条目非常的多,一个屏幕放不下,因此我们需要一个水平滚动条来盛放这很多的条目。

      ②我们看到底部的内容随着指示条再不断滑动,因此底部内容是一个viewpager。

      ③下面就是这个控件最关键的部分,就是指示条随着viewpager的内容相互滚动,这涉及到一定逻辑,下面我会阐述这方面的逻辑内容。

      说了一大段开场白以后,我们就应该庖丁解牛般的实现我们控件,废话少说,直接上代码,首先,粉墨登场是头部控件xml布局文件。

      

    <!-- 
      头部标题栏 
     包含一个水平滚动条
     单选按钮组
     以及一个标题指示条
     -->
    <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 放在一个单项按钮组中。当然,还需要一个指示翻到第几页的指示条。

      接下来,就是重头戏了,这个自定义控件逻辑控制。我们看一下他的流程图

      

      通过上述流程图,我们可以得出指示条伴随头部栏与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

  • 相关阅读:
    [LeetCode 1029] Two City Scheduling
    POJ 2342 Anniversary party (树形DP入门)
    Nowcoder 106 C.Professional Manager(统计并查集的个数)
    2018 GDCPC 省赛总结
    CF 977 F. Consecutive Subsequence
    Uva 12325 Zombie's Treasure Chest (贪心,分类讨论)
    Poj 2337 Catenyms(有向图DFS求欧拉通路)
    POJ 1236 Network of Schools (强连通分量缩点求度数)
    POJ 1144 Network (求割点)
    POJ 3310 Caterpillar(图的度的判定)
  • 原文地址:https://www.cnblogs.com/manuosex/p/5017526.html
Copyright © 2011-2022 走看看