• 老猪带你玩转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

  • 相关阅读:
    java执行构造器和初始化字段的顺序
    java语言中的varargs
    对Java语言的byte类型变量进行无符号提升
    VisualStudio 切换帐号 (原帐号已过期且无法登录时用)
    C/C++ 的关系运算符采用短路运算
    实现std::string的ltrim、rtrim和trim方法
    Excel 用于批量把单元格设置为"文本格式保存的数字"的宏
    为什么要用webUI?
    CEF3中js调用delphi内部方法
    2016-1-1最新版本的linphone-android在mac上编译通过,同时建立了IDEA工程
  • 原文地址:https://www.cnblogs.com/manuosex/p/5017526.html
Copyright © 2020-2023  润新知