当前位置:K88软件开发文章中心编程语言LinuxLinux01 → 文章内容

Android-导航栏特效-新闻类APP(仿iOS版网易新闻今日头条的文字渐变缩放特效)

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-4 9:00:53

-->

好久没有写文章了,慢慢的自己工作中遇到的问题不做积累,下次遇到还会忘。哎。。。。

周日无聊的单身程序员-唯有程序你懂的…
写着程序听着歌也是极好的!!

最近工作中要实现类似 今日头条等新闻类APP顶部导航条的效果 ,不过我们这效果切换时要加上文字颜色的渐变和缩放。
git图片比较大,耐心等待哦,小宝贝~~

1.gif

s4.gif

一:分析
今天我们要实现这种特效。
用到的开源项目有:master-nineoldandroids-library.jar这个jar包,这个是向下兼容的jar包,包括android一系列的动画。
首先我们说一下这种 日头条等新闻类APP 的基本实现是ViewPage+Fragment+HorizontalScrollView
我们今天说的就是这个HorizontalScrollView的特效。
实现原理图:

20150329110204358.png

相信大家已经明白了大概
就是:最初时我们 初始化textview 并把选中的和正常的textview 初始化。就是上图中的framelayout中的2个textview 放到集合 HashMap<String, View>()中。用于保持所有textview的状态。
至于代码怎么写呢?!
android系统给我们提供了一个叫PagerSlidingTabStrip的类,在v4包中。我们把java中考出来放到我们的项目中,修改其中的代码就可以。
我们通过viewpage来控制导航条。把viewpage传到PagerSlidingTabStrip中,并设置监听器,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setViewPager</span><span class="hljs-params">(ViewPager pager)</span> </span>{
        <span class="hljs-keyword">this</span>.pager = pager;

        <span class="hljs-keyword">if</span> (pager.getAdapter() == <span class="hljs-keyword">null</span>) {
            <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(
                    <span class="hljs-string">"ViewPager does not have adapter instance."</span>);
        }

        pager.setOnPageChangeListener(pageListener);

        notifyDataSetChanged();
    }

二、获取用户切换时当前View和切换至的目的View。

ViewPager也需要监听用户的手势,所以肯定提供了某个方法。于是纵观ViewPager的方法,发现了一个叫做 onPageScrolled(int position, float positionOffset, int positionOffsetPixels)的方法~~
没错就是这个方法:在页面滚动时调用~
下面仔细研究下这几个参数:
直接说测试结果:
在非第一页与最后一页时,滑动到下一页,position为当前页位置;滑动到上一页:position为当前页-1
positionOffset 滑动到下一页,[0,1)区间上变化;滑动到上一页:(1,0]区间上变化
positionOffsetPixels这个和positionOffset很像:滑动到下一页,[0,宽度)区间上变化;滑动到上一页:(宽度,0]区间上变化
第一页时:滑动到上一页position=0 ,其他基本为0 ;最后一页滑动到下一页 position为当前页位置,其他两个参数为0

豁然发现,我们需要的步骤的第二步解决了,positionOffset很适合作为,渐变,缩放的控制参数;positionOffsetPixels则可以作为平移等的控制参数。
那么如何获得当前View和目的View呢:
分享几个我的歧途:
1、【错误】我通过getChildAt(position),getChildAt(position+1),getChildAt(position-1)获得滑动时,左右的两个View;乍一看,还真觉得不错~在代码写出来,再乍效果也出不来错误原因:我们忽略一个特别大的东西,ViewPager的机制,滑动时动态加载和删除View,ViewPager其实只会维持2到3个View,而position的范围基本属于无限~~
2、【错误】我通过getCurrentItem获得当前的位置,然后+1,-1获得后一个或者前一个正在窃喜,赶快代码改过来,效果怎么也不对,乱七八糟的仔细观察日志,这个getCurrentItem当用户手指离开的屏幕,Page还在动画执行时,就改变了难怪~整个滑动过程并不是固定的唉,心都碎了~
3、【错误】position在整个滑动的过程中是不变化的,而且ViewPager会保存2个或3个View;那么我考虑,如果是第一页、或者最后一页那么我取getChildAt(0)和getChildAt(1),如果在其他页面则为getChildAt(0),getChildAt(2),然后经过一系列的变化~我想这会总该对了吧,于是我遇到第一问题,第一页的时候,不管左右position都为0,尼玛,这哪个为左View,哪个为右View~~
说了这么多错误,大家可以绕过这些弯路,也能从这些弯路里面看出点什么~
下面说正确的,其实ViewPager在添加一个View或者销毁一个View时,是我们自己的PageAdapter中控制的,于是我们可以在ViewPager里面维系一个HashMap<Position,View>,然后滑动的时候,通过get(position)取出,比如上述效果,始终是右边的View变化,要么从小到大,要么从大到小
那么滑倒下一页:左边的View:map.get(position) ,右边的View : map.get(position+1) .
那么滑倒上一页:左边的View : map.get(position) , 右边的View : map.get(position+1) , 一样的,因为滑到上一页,position为当前页-1

关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<pre name=<span class="hljs-string">"code"</span> <span class="hljs-class"><span class="hljs-keyword">class</span></span>=<span class="hljs-string">"java"</span>>    <span class="hljs-keyword">private</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PageListener</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OnPageChangeListener</span> </span>{
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> oldPosition = <span class="hljs-number">0</span>;

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onPageScrolled</span><span class="hljs-params">(<span class="hljs-keyword">int</span> position, <span class="hljs-keyword">float</span> positionOffset,
                <span class="hljs-keyword">int</span> positionOffsetPixels)</span> </span>{
            currentPosition = position;
            currentPositionOffset = positionOffset;

            scrollToChild(position, (<span class="hljs-keyword">int</span>) (positionOffset * tabsContainer
                    .getChildAt(position).getWidth()));

            invalidate();

            <span class="hljs-keyword">if</span> (delegatePageListener != <span class="hljs-keyword">null</span>) {
                delegatePageListener.onPageScrolled(position, positionOffset,
                        positionOffsetPixels);
            }

            <span class="hljs-keyword">if</span> (mState == State.IDLE && positionOffset > <span class="hljs-number">0</span>) {
                oldPage = pager.getCurrentItem();
                mState = position == oldPage ? State.GOING_RIGHT
                        : State.GOING_LEFT;
            }
            <span class="hljs-keyword">boolean</span> goingRight = position == oldPage;
            <span class="hljs-keyword">if</span> (mState == State.GOING_RIGHT && !goingRight)
                mState = State.GOING_LEFT;
            <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (mState == State.GOING_LEFT && goingRight)
                mState = State.GOING_RIGHT;

            <span class="hljs-keyword">float</span> effectOffset = isSmall(positionOffset) ? <span class="hljs-number">0</span> : positionOffset;

            View mLeft = tabsContainer.getChildAt(position);
            View mRight = tabsContainer.getChildAt(position + <span class="hljs-number">1</span>);

            <span class="hljs-keyword">if</span> (effectOffset == <span class="hljs-number">0</span>) {
                mState = State.IDLE;
            }

            <span class="hljs-keyword">if</span> (mFadeEnabled)
                animateFadeScale(mLeft, mRight, effectOffset, position);

        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onPageScrollStateChanged</span><span class="hljs-params">(<span class="hljs-keyword">int</span> state)</span> </span>{
            <span class="hljs-keyword">if</span> (state == ViewPager.SCROLL_STATE_IDLE) {
                scrollToChild(pager.getCurrentItem(), <span class="hljs-number">0</span>);
                mFadeEnabled = <span class="hljs-keyword">true</span>;
            }

            <span class="hljs-keyword">if</span> (delegatePageListener != <span class="hljs-keyword">null</span>) {
                delegatePageListener.onPageScrollStateChanged(state);
            }
        }

        <span class="hljs-annotation">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onPageSelected</span><span class="hljs-params">(<span class="hljs-keyword">int</span> position)</span> </span>{
            <span class="hljs-comment">// selectedPosition = position;</span>
            <span class="hljs-comment">// updateTabStyles();</span>
            currentPosition = position;

            <span class="hljs-comment">// set old view statue</span>
            ViewHelper.setAlpha(tabViews.get(oldPosition).get(<span class="hljs-string">"normal"</span>), <span class="hljs-number">1</span>);
            ViewHelper.setAlpha(tabViews.get(oldPosition).get(<span class="hljs-string">"selected"</span>), <span class="hljs-number">0</span>);
            View v_old = tabsContainer.getChildAt(oldPosition);
            ViewHelper.setPivotX(v_old, v_old.getMeasuredWidth() * <span class="hljs-number">0.5f</span>);
            ViewHelper.setPivotY(v_old, v_old.getMeasuredHeight() * <span class="hljs-number">0.5f</span>);
            ViewHelper.setScaleX(v_old, <span class="hljs-number">1f</span>);
            ViewHelper.setScaleY(v_old, <span class="hljs-number">1f</span>);

            <span class="hljs-comment">// set new view statue</span>
            ViewHelper.setAlpha(tabViews.get(position).get(<span class="hljs-string">"normal"</span>), <span class="hljs-number">0</span>);
            ViewHelper.setAlpha(tabViews.get(position).get(<span class="hljs-string">"selected"</span>), <span class="hljs-number">1</span>);
            View v_new = tabsContainer.getChildAt(position);
            ViewHelper.setPivotX(v_new, v_new.getMeasuredWidth() * <span class="hljs-number">0.5f</span>);
            ViewHelper.setPivotY(v_new, v_new.getMeasuredHeight() * <span class="hljs-number">0.5f</span>);
            ViewHelper.setScaleX(v_new, <span class="hljs-number">1</span> + ZOOM_MAX);
            ViewHelper.setScaleY(v_new, <span class="hljs-number">1</span> + ZOOM_MAX);

            <span class="hljs-keyword">if</span> (delegatePageListener != <span class="hljs-keyword">null</span>) {
                delegatePageListener.onPageSelected(position);
            }
            <span class="hljs-comment">// oldPosition = selectedPosition;</span>
            oldPosition = currentPosition;

        }

    }

可以看到代码:缩放view很关键:

1
2
3
4
5
View v_old = tabsContainer.getChildAt(oldPosition);
            ViewHelper.setPivotX(v_old, v_old.getMeasuredWidth() * <span class="hljs-number">0.5f</span>);
            ViewHelper.setPivotY(v_old, v_old.getMeasuredHeight() * <span class="hljs-number">0.5f</span>);
            ViewHelper.setScaleX(v_old, <span class="hljs-number">1f</span>);
            ViewHelper.setScaleY(v_old, <span class="hljs-number">1f</span>);

找到view的中心点即:setPivotX setPivotY 然后对X轴Y轴缩放。1为原始大小。>1放大,<1 且>0 缩小。
关键代码是:onPageScrolled 方法的底2个参数positionOffset 滑动的百分比。
渐变通过animateFadeScale这个方法控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">animateFadeScale</span><span class="hljs-params">(View left, View right,
            <span class="hljs-keyword">float</span> positionOffset, <span class="hljs-keyword">int</span> position)</span> </span>{

        <span class="hljs-keyword">if</span> (mState != State.IDLE) {
            <span class="hljs-keyword">if</span> (left != <span class="hljs-keyword">null</span>) {
                ViewHelper.setAlpha(tabViews.get(position).get(<span class="hljs-string">"normal"</span>),
                        positionOffset);
                ViewHelper.setAlpha(tabViews.get(position).get(<span class="hljs-string">"selected"</span>),
                        <span class="hljs-number">1</span> - positionOffset);

                <span class="hljs-keyword">float</span> mScale = <span class="hljs-number">1</span> + ZOOM_MAX - ZOOM_MAX * positionOffset;

                ViewHelper.setPivotX(left, left.getMeasuredWidth() * <span class="hljs-number">0.5f</span>);
                ViewHelper.setPivotY(left, left.getMeasuredHeight() * <span class="hljs-number">0.5f</span>);
                ViewHelper.setScaleX(left, mScale);
                ViewHelper.setScaleY(left, mScale);

            }
            <span class="hljs-keyword">if</span> (right != <span class="hljs-keyword">null</span>) {
                ViewHelper.setAlpha(tabViews.get(position + <span class="hljs-number">1</span>).get(<span class="hljs-string">"normal"</span>),
                        <span class="hljs-number">1</span> - positionOffset);
                ViewHelper.setAlpha(tabViews.get(position + <span class="hljs-number">1</span>).get(<span class="hljs-string">"selected"</span>),
                        positionOffset);

                <span class="hljs-keyword">float</span> mScale = <span class="hljs-number">1</span> + ZOOM_MAX * positionOffset;

                ViewHelper.setPivotX(right, right.getMeasuredWidth() * <span class="hljs-number">0.5f</span>);
                ViewHelper.setPivotY(right, right.getMeasuredHeight() * <span class="hljs-number">0.5f</span>);
                ViewHelper.setScaleX(right, mScale);
                ViewHelper.setScaleY(right, mScale);

            }
        }
    }

在你activity/引用的地方 中你可以直接设置TAB的颜色大小,正常色,选中色等。EG:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<span class="hljs-comment">/**
     * 对PagerSlidingTabStrip的各项属性进行赋值。
     */</span>
    <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setTabsValue</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-comment">// 设置Tab是自动填充满屏幕的</span>
        tabs.setShouldExpand(<span class="hljs-keyword">true</span>);
        <span class="hljs-comment">// 设置Tab的分割线是透明的</span>
        tabs.setDividerColor(Color.TRANSPARENT);
        <span class="hljs-comment">// 设置Tab底部线的高度</span>
        tabs.setUnderlineHeight((<span class="hljs-keyword">int</span>) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, <span class="hljs-number">1</span>, dm));
        <span class="hljs-comment">// 设置Tab Indicator的高度</span>
        tabs.setIndicatorHeight((<span class="hljs-keyword">int</span>) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, <span class="hljs-number">4</span>, dm));
        <span class="hljs-comment">// 设置Tab标题文字的大小</span>
        tabs.setTextSize((<span class="hljs-keyword">int</span>) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_SP, <span class="hljs-number">16</span>, dm));
        <span class="hljs-comment">// 设置Tab Indicator的颜色</span>
        tabs.setIndicatorColor(Color.parseColor(<span class="hljs-string">"#45c01a"</span>));
        <span class="hljs-comment">// 设置选中Tab文字的颜色 (这是我自定义的一个方法)</span>
        tabs.setSelectedTextColor(Color.parseColor(<span class="hljs-string">"#45c01a"</span>));
        <span class="hljs-comment">//设置正常Tab文字的颜色 (这是我自定义的一个方法)</span>
        tabs.setTextColor(Color.parseColor(<span class="hljs-string">"#C231C7"</span>));
        <span class="hljs-comment">// 取消点击Tab时的背景色</span>
        tabs.setTabBackground(<span class="hljs-number">0</span>);
    }

源码:
可以使用依赖库,github上都有说明
github地址:
https://github.com/ta893115871/PagerSlidingTabStrip/

记得start哦


Android-导航栏特效-新闻类APP(仿iOS版网易新闻今日头条的文字渐变缩放特效)