美文网首页
自定义波纹特效的TabLayout

自定义波纹特效的TabLayout

作者: 0a2868f025e0 | 来源:发表于2017-05-17 19:36 被阅读317次

1 引言

1.1 背景。

在以往的开发项目VR助手中有一个交互,就是利用波纹的指示器来实现Tab的切换。

2 交互方式

Paste_Image.png

1)排行向全部过度时,有一个波纹走向:从初始点往高点移动。

2)全部向排行过度,由高点向低点移动,到排行这个按钮时时为最高峰。

从上图可以看到,当排行向全部的Tab划过时,需要有一个波纹的走向,以现有的Metrial Design提供的TabLayout是没法实现该效果的。

3 问题

1.TabLayout中的指示器是如何做到过渡的效果?

2.根据波纹的走向要使用什么数学模型?

4 解决思路

根据第一个问题,利用手机上的开发者模式中,打开显示Layout布局方式,从中看到,TabView是多个,而指示器应该是一个。为了验证整个问题,决定从源码上分析整个TabLayout的实现方式,来验证自己的判断,并将原生的部分源码COPY出来,改造一个新的TabLayout。

Paste_Image.png

从上图可以看出,TabLayout分为几个模块:

1.SlidingTabStrip:TabView的容器类,用于承载TabView以及TabView滑动过程中,绘制的指示器。

2.TabView:一个Tab的View控件,支持自定义Tab,设置Tab的icon,text等,并且可以做特殊的特效控件。

3.Tab:TabView的参数类。

按照项目协作的方式理解就是:

1.RippleTabLayout就是一个领导,领导所要做的事有:

1)指派员工处理某件事(addTab,removeTab,selectTab,传递外部人员给与的参数)。

2)跟外部人员对接本项目(ViewPager,暴露监听回调。

2.SlidingTabStrip:程序员

1)努力实现领导下达的任务(onDraw):根据领导下发的外部对接参数,来绘制指示器。

2)由于SlidingTabStrip继承了LinearLayout,因此,也具备了add、remove、select的操作。

这时候,外部人员(ViewPager)传入参数,告知领导RippleTabLayout(positionOffset),程序员为了保证动态的效果,加入了动画(ValueAnimator)。当每接收到一次参数时,重新绘制一次指示器。

经验证发现,真正能实现波纹动效方面的是程序员(SlidingTabStrip)而非领导,那么我们要如何才能实现这种动态效果呢。当然还是让程序员来实现最好。

于是,我们在SlidingTabStrip中引入的高斯函数,为其绘制出动态效果。

Paste_Image.png

高斯函数,广泛用于计算机图形学中,在起初进行开发前,数学模型采用的是其它线性模型,经过对交互的揣摩,后面选择了高斯滤波。在这里感谢谢炜斌、曾承航和已离职的陈鹏同学,大家针对高斯函数的方式进行了优化,并给予了算法。

5 程序改造

既然有了思路,就要着手解决这个交互。

1)提取原TbaLayout中的AnimationUtils、TabView、ViewUtils、ViewUtilsLopLipop进行部分代码改造。

2)重写SlidingTabStrip,并在SlidingTabStrip的onDraw方法中加入优化后的高斯滤波算法。核心代码如下:

//绘制高斯函数,根据线性大小计算值
private double getGussion(double lineX, double GussionHight, double GussionMu)
{  
    double result = 0;   
    result = -GussionHight * ( Math.pow(Math.E, -(lineX - GussionMu) * (lineX - GussionMu) / (2 *   dpToPx(8) * dpToPx(8)))) + getHeight() - 3 ;   
    return result;
}

3)每一次的移动,手没放开,都在不断的onDraw

protected void onDraw(Canvas canvas) 
{ 
    super.onDraw(canvas);    
    Log.i("draw", "mGussionHeightOffset start= " );
    Path path = new Path();
    path.moveTo(0, getHeight());
    for (int i = 0; i < getWidth(); i++){
        double y1 = getGussion(i, dpToPx(15) * Math.abs(mGussionHeightOffset - 0.5),   (mIndicatorRight + mIndicatorLeft) / 2);        
        double y2 = getGussion(i + 1, dpToPx(15) * Math.abs(mGussionHeightOffset - 0.5), (mIndicatorRight + mIndicatorLeft) / 2);      
        path.quadTo(i, (float) y1, i + 1 , (float)y2);  
    }   
    canvas.drawPath(path, mSelectedIndicatorPaint);  
    Log.i("draw", "mGussionHeightOffset end= " );  
}

6 总结

代码能力编写再强,也要学会如何用数学模型思维来解决问题。

以下是该控件实现的相关源码:
https://github.com/RichsJeson/Android-UI/tree/master/AndroidUI/RippleLayout

相关文章

网友评论

      本文标题:自定义波纹特效的TabLayout

      本文链接:https://www.haomeiwen.com/subject/xffjxxtx.html