HorizontalScrollView 仿真 tabLayout

HorizontalScrollView 仿真 tabLayout别人微博的网址http://blog.csdn.net/u013835855/article/details/71159888目前滑动指示器最著名的是JakeWarton的ViewpagerIndicator,用别人的东西固然方便,但是也带来很多使用上的疑惑,这篇博客,我们使用HorizontalScrollView自己写一个viewPager指示器。这里首先说一下很多自己写的indi

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

别人微博的 网址 http://blog.csdn.net/u013835855/article/details/71159888

目前滑动指示器最著名的是JakeWarton的ViewpagerIndicator,用别人的东西固然方便,但是也带来很多使用上的疑惑,这篇博客,我们使用HorizontalScrollView自己写一个viewPager指示器。

这里首先说一下很多自己写的indicator只限于可视范围内不能移动的指示器,所以tab的数量有限,一般最多五个就已经很拥挤了,可是我们发现开源的ViewpagerIndicator有一个很棒的效果就是不用限定tab的个数,并且当前选中的tab将处于中间位置(两边不可滑动范围除外),这一点我便想到了利用HorizontalScrollView来实现这个效果。而tab的显示我使用TextView就行动态加载,然后把tab放到HorizontalScrollView中,在这里注意一个问题,那就是HorizontalScrollView本身的子view个数是有限定的,只能是一个,这一点跟scrollview一样,源码是这样的:

  1. @Override  
  2.     public void addView(View child) {  
  3.         if (getChildCount() > 0) {  
  4.             throw new IllegalStateException(“HorizontalScrollView can host only one direct child”);  
  5.         }  
  6.   
  7.         super.addView(child);  
  8.     }  

我们可以看到如果getChildCount()的个数大于零,就会抛出异常,所以这里我使用一个LinearLayout先包裹所有的textview然后再把LinearLayout放入HorizontalScrollView中,这样就不会抛异常了。代码如下:

  1. LinearLayout linearLayout = new LinearLayout(context);  
  2.        linearLayout.setOrientation(LinearLayout.HORIZONTAL);  
  3.        linearLayout.setLayoutParams(new LinearLayout.LayoutParams(count*tabWidth, LinearLayout.LayoutParams.MATCH_PARENT));  
  4.        for (int i = 0; i < count; i++)  
  5.        {  
  6.            TextView tv = new TextView(getContext());  
  7.            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tabWidth,  
  8.                    LinearLayout.LayoutParams.MATCH_PARENT);  
  9.            tv.setGravity(Gravity.CENTER);  
  10.            tv.setTextColor(COLOR_TEXT_NORMAL);  
  11.            tv.setText(titles[i]);  
  12.            tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);//字体大小  
  13.            tv.setLayoutParams(lp);  
  14.            final int finalI = i;  
  15.            tv.setOnClickListener(new OnClickListener()  
  16.            {  
  17.                @Override  
  18.                public void onClick(View v)  
  19.                {  
  20.                    if(viewPager!=null){  
  21.                        viewPager.setCurrentItem(finalI);  
  22.                    }  
  23.                }  
  24.            });  
  25.            linearLayout.addView(tv);  
  26.        }  
  27.        addView(linearLayout);  

而HorizontalScrollView中那个下划线效果,通过dispatchDraw方法实现

  1. @Override  
  2.     protected void dispatchDraw(Canvas canvas)  
  3.     {  
  4.         super.dispatchDraw(canvas);  
  5.         canvas.save();  
  6.         canvas.translate(mTranslationX, getHeight() – lineheight);  
  7.         canvas.drawLine(0, 0, tabWidth, 0, mPaint);//(startX, startY, stopX, stopY, paint)  
  8.         canvas.restore();  
  9.     }  

其滑动效果则通过监听viewpager滑动的OnPageChangeListener接口中的onPageScrolled函数实现,我们知道onPageScrolled有三个参数起源吗如下:

  1. /** 
  2.          * This method will be invoked when the current page is scrolled, either as part 
  3.          * of a programmatically initiated smooth scroll or a user initiated touch scroll. 
  4.          * 
  5.          * @param position Position index of the first page currently being displayed. 
  6.          *                 Page position+1 will be visible if positionOffset is nonzero. 
  7.          * @param positionOffset Value from [0, 1) indicating the offset from the page at position. 
  8.          * @param positionOffsetPixels Value in pixels indicating the offset from position. 
  9.          */  
  10.         void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);  

通过源码可知,第一个参数是当前的位置,第二个参数比较有意思,是指滑动距离相对于整个viewpager宽度的百分比,第三个是滑动的真正距离。这里我们利用第二个参数实现跟随滑动效果。这里我封装了一个函数如下:

  1. public void scroll(int position, float offset)  
  2.     {  
  3.         mTranslationX = tabWidth * (position + offset);  
  4.         scrollTo((int)mTranslationX-(SCREEN_WIDTH-tabWidth)/2, 0);  
  5.         invalidate();  
  6.     }  

解释一下,我们将position和offse(百分比)传进去首先计算下划线应该滑动到的初始位置,然后利用scrollTo函数将HorizontalScrollView进行移动,最后重绘,于是就到达了滑动跟随的效果。全部源码如下:

  1. package com.zp.scrolltest;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.support.v4.view.ViewPager;  
  8. import android.util.AttributeSet;  
  9. import android.util.TypedValue;  
  10. import android.view.Gravity;  
  11. import android.view.View;  
  12. import android.widget.HorizontalScrollView;  
  13. import android.widget.LinearLayout;  
  14. import android.widget.TextView;  
  15.   
  16. /** 
  17.  * Created by ez on 2017/5/4. 
  18.  */  
  19.   
  20. public class MyIndicator extends HorizontalScrollView implements ViewPager.OnPageChangeListener{  
  21.   
  22.     private static final int COLOR_TEXT_NORMAL = 0xFF000000;  
  23.     private static final int COLOR_INDICATOR_COLOR = Color.BLACK;  
  24.   
  25.     private Context context;  
  26.     private  int tabWidth;  
  27.     private String[] titles;  
  28.     private int count;  
  29.     private Paint mPaint;  
  30.     private float mTranslationX;  
  31.     private ViewPager viewPager;  
  32.     private int SCREEN_WIDTH;  
  33.     private float lineheight = 2.0f;  
  34.   
  35.     public MyIndicator(Context context) {  
  36.         this(context, null);  
  37.     }  
  38.   
  39.     public MyIndicator(Context context, AttributeSet attrs) {  
  40.         super(context, attrs);  
  41.         init(context);  
  42.     }  
  43.   
  44.     public MyIndicator(Context context, AttributeSet attrs, int defStyleAttr) {  
  45.         super(context, attrs, defStyleAttr);  
  46.         init(context);  
  47.     }  
  48.   
  49.     private void init(Context context){  
  50.         this.context = context;  
  51.         mPaint = new Paint();  
  52.         mPaint.setColor(COLOR_INDICATOR_COLOR);  
  53.         mPaint.setStrokeWidth(lineheight);//底部指示线的宽度  
  54.         setHorizontalScrollBarEnabled(false);  
  55.         SCREEN_WIDTH = context.getResources().getDisplayMetrics().widthPixels;  
  56.     }  
  57.   
  58.     public void setLineheight(float height){  
  59.         this.lineheight = height;  
  60.         mPaint.setStrokeWidth(lineheight);//底部指示线的宽度  
  61.     }  
  62.   
  63.     public void setViewPager(ViewPager viewPager){  
  64.         this.viewPager = viewPager;  
  65.         viewPager.addOnPageChangeListener(this);  
  66.     }  
  67.   
  68.     public void setTitles(String[] titles){  
  69.         this.titles = titles;  
  70.         count = titles.length;  
  71.         tabWidth = SCREEN_WIDTH/4;  
  72.         generateTitleView();  
  73.     }  
  74.   
  75.     @Override  
  76.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  77.         super.onSizeChanged(w, h, oldw, oldh);  
  78.         tabWidth = SCREEN_WIDTH/4;  
  79.     }  
  80.   
  81.     @Override  
  82.     protected void dispatchDraw(Canvas canvas)  
  83.     {  
  84.         super.dispatchDraw(canvas);  
  85.         canvas.save();  
  86.         canvas.translate(mTranslationX, getHeight() – lineheight);  
  87.         canvas.drawLine(0, 0, tabWidth, 0, mPaint);//(startX, startY, stopX, stopY, paint)  
  88.         canvas.restore();  
  89.     }  
  90.   
  91.     public void scroll(int position, float offset)  
  92.     {  
  93.         mTranslationX = tabWidth * (position + offset);  
  94.         scrollTo((int)mTranslationX-(SCREEN_WIDTH-tabWidth)/2, 0);  
  95.         invalidate();  
  96.     }  
  97.   
  98.     private void generateTitleView()  
  99.     {  
  100.         if (getChildCount() > 0)  
  101.             this.removeAllViews();  
  102.         count = titles.length;  
  103.   
  104.         LinearLayout linearLayout = new LinearLayout(context);  
  105.         linearLayout.setOrientation(LinearLayout.HORIZONTAL);  
  106.         linearLayout.setLayoutParams(new LinearLayout.LayoutParams(count*tabWidth, LinearLayout.LayoutParams.MATCH_PARENT));  
  107.         for (int i = 0; i < count; i++)  
  108.         {  
  109.             TextView tv = new TextView(getContext());  
  110.             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tabWidth,  
  111.                     LinearLayout.LayoutParams.MATCH_PARENT);  
  112.             tv.setGravity(Gravity.CENTER);  
  113.             tv.setTextColor(COLOR_TEXT_NORMAL);  
  114.             tv.setText(titles[i]);  
  115.             tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);//字体大小  
  116.             tv.setLayoutParams(lp);  
  117.             final int finalI = i;  
  118.             tv.setOnClickListener(new OnClickListener()  
  119.             {  
  120.                 @Override  
  121.                 public void onClick(View v)  
  122.                 {  
  123.                     if(viewPager!=null){  
  124.                         viewPager.setCurrentItem(finalI);  
  125.                     }  
  126.                 }  
  127.             });  
  128.             linearLayout.addView(tv);  
  129.         }  
  130.         addView(linearLayout);  
  131.     }  
  132.   
  133.     @Override  
  134.     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {  
  135.         scroll(position, positionOffset);  
  136.     }  
  137.   
  138.     @Override  
  139.     public void onPageSelected(int position) {  
  140.   
  141.     }  
  142.   
  143.     @Override  
  144.     public void onPageScrollStateChanged(int state) {  
  145.   
  146.     }  
  147. }  

最后说一下使用,首先在XML中像普通组件一样使用:

  1. <?xml version=“1.0” encoding=“utf-8”?>  
  2. <LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”  
  3.     xmlns:tools=“http://schemas.android.com/tools”  
  4.     android:id=“@+id/activity_main”  
  5.     android:orientation=“vertical”  
  6.     android:layout_width=“match_parent”  
  7.     android:layout_height=“match_parent”  
  8.     tools:context=“com.zp.scrolltest.MainActivity”>  
  9.   
  10.     <com.zp.scrolltest.MyIndicator  
  11.         android:layout_width=“wrap_content”  
  12.         android:layout_height=“40dp”  
  13.         android:background=“@android:color/holo_blue_bright”  
  14.         android:id=“@+id/indicador”/>  
  15.   
  16.     <android.support.v4.view.ViewPager  
  17.         android:layout_width=“match_parent”  
  18.         android:layout_height=“match_parent”  
  19.         android:id=“@+id/pager”/>  
  20.   
  21. </LinearLayout>  

接下来在Java代码中:

  1. indicador = (MyIndicator) findViewById(R.id.indicador);  
  2.         titles = new String[]{
    “a”, “b”, “c”, “d”, “e”, “f”};  
  3.         indicador.setTitles(titles);  
  4.   
  5.         viewPager = (ViewPager) findViewById(R.id.pager);  
  6.           
  7.         viewPager.setAdapter(mAdapter);  
  8.         indicador.setViewPager(viewPager); 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/159392.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • android之在activity中控制另一个activity的UI更新_如何在activity之间传递handler

    遇到一个问题,需要在一个activity中控制另一个acitivity做一些更新,没想到传递handler的方法,通过以下方式解决。1.在MyAPP中定义属性handlerpackage jason.com;import jason.com.MasterActivity.MyHandler;import android.app.Application;/*** 自己

    2022年3月10日
  • pycharm 中文输入_pycharm中文输入法

    pycharm 中文输入_pycharm中文输入法1.Pycharm编译器中英文切换1.左上角打开file(文件)—>setting(设置)—plugins(插件)2.搜索chinese,点击安装3.安装完根据提示重启就行2.pycharm输入法不能输入中文1.找到pycharm的bin文件(我的是在/opt/pycharm/bin)2.打开pycharm.sh,在当前区域添加以下代码(我的是第144行)。如果是fcitx输入框架,则ibus换成fcitxexportLC_ALL=zh_CN.UTF-8expor

    2022年8月25日
  • Python 学习笔记 列表 for 循环 xxx XXX

    Python 学习笔记 列表 for 循环 xxx XXXPython学习笔记列表for循环xxxXXXprint(“-“*30)magicians=[‘alice’,’david’,’carolina’]formagicianinmagicians: print(magician)formagicianinmagicians: print(magician.title()+”,thatwasagreattrick!”) print(“I…

    2022年8月22日
  • git命令删除分支_git删除一个分支

    git命令删除分支_git删除一个分支git命令删除分支应用场景:有时我们已经在gitlab或者gitee上面已经删除分支,但是本地编辑器gitbranch的时候依然有该分支,我们想删除;亦或者想在本地直接删除远程的分支假设,你想删除本地testone分支gitbranch查看本地分支,比如:testonetesttwo两个分支gitcheckouttesttwo切换到testtwo分支,因为你想删除testone执行gitbranch-dtestone即可另外:

    2022年8月31日
  • VCLibs库文件包下载_怎么使用已有的加速包

    VCLibs库文件包下载_怎么使用已有的加速包本文以MDI应用程序为例说明如何在已有的VC++工程中使用BCG界面库,我的开发环境为VS2003。1、将BCG/BCGCBPro目录路径添加到“项目属性->C/C++->常规->附加包含目录”中,同时将BCG/Bin目录路径添加到“项目属性->链接器->常规->附加库目录”中。2、确保在CWinApp派生类(设为CMyApp)的InitInstance()成员函数中调用AfxOl

    2022年10月8日
  • 光猫 路由器 ipv6_ipv6光猫设置

    光猫 路由器 ipv6_ipv6光猫设置电信光猫桥接+ML固件路由器实现ipv6网站访问

    2022年10月8日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号