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(00, 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)/20);  
  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(00, 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)/20);  
  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); 

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • java 动态规划 背包问题[通俗易懂]

    java 动态规划 背包问题[通俗易懂]背包问题具体例子:假设现有容量10kg的背包,另外有3个物品,分别为a1,a2,a3。物品a1重量为3kg,价值为4;物品a2重量为4kg,价值为5;物品a3重量为5kg,价值为6。将哪些物品放入背包可使得背包中的总价值最大?首先想到的,一般是穷举法,一个一个地试,对于数目小的例子适用,如果容量增大,物品增多,这种方法就无用武之地了。  其次,可以先把价值最大的物体放入,这已经是贪

  • nagios监控三部曲之——nagios的安装与配置(1)

    nagios监控三部曲之——nagios的安装与配置(1)

  • INTERLLij IDEA 修改背景颜色护眼[通俗易懂]

    INTERLLij IDEA 修改背景颜色护眼[通俗易懂]IDEA的默认颜色为黑色,确实很酷,第一眼就被它的界面所惊艳到了!不过软件的默认字体太小,对于我这个有着500多度近视的人来说简直痛苦,特地整理了一些修改背景颜色的方法,供大家参考。1.IntelliJIDEA设置菜单栏字体:File—Setting—Appearance&amp;Behavior—Appearance—Overridedefaul…

  • pytest skipif_pytest conftest.py文件

    pytest skipif_pytest conftest.py文件前言pytest.mark.skip可以标记无法在某些平台上运行的测试功能,或者您希望失败的测试功能Skip和xfail:处理那些不会成功的测试用例你可以对那些在某些特定平台上不能运行的测试用

  • 数据仓库的概念

    数据仓库的概念

  • oracle触发器实例

    oracle触发器实例最近有一个需求,一个数据库的表在插入和删除的时候另外一个数据库中的表也做相应的操作。我的想法是1.首先两个数据库可以连接,通过dblink可以解决。2.建立插入和删除才能触发的触发器。直接上代码createorreplacetriggersynch_useridafterinsertordeleteoneosoperatorFOREACHROW–每一行触发一次…

发表回复

您的电子邮箱地址不会被公开。

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