转载请注明出处,谢谢~
今天要说一个简单但不好想的效果实现。代码绝对简单,实现绝对easy,就是你可能想不到而已。
不多说,上效果图。第一个效果是仿最美应用的滑动颜色变化,第二个是我项目中要用的效果,实现后我就贴出来了,开源嘛。
下面分别说说这两个实现的原理和想法。
首先我们看纯色的第一张gif,纯色的渐变还是容易一些的。
1.实现一个ViewPager,因为我们要实现的是,随着手指的移动,viewpager的背景色改变,所以暂时的想法是,不需要自定义viewpager。
2.给背景设置一个纯色的color。
3.viewpager的滑动,如何获取,如何处理
4.如何让颜色渐变,怎么获取渐变值
下面我们一个一个的解决。
1.使用viewpager貌似是很简单的,这里不复述了,代码我贴上:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp" android:id="@+id/ll" android:orientation="vertical" > <TextView android:padding="10dp" android:layout_width="match_parent" android:gravity="center_horizontal" android:layout_height="wrap_content" android:textColor="#ff000000" android:text="这是title" /> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" > </android.support.v4.view.ViewPager> </LinearLayout>
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); llLayout = (LinearLayout) findViewById(R.id.ll); viewpager = (ViewPager) findViewById(R.id.viewpager); fragment = new ImageFragment(); fragment2 = new ImageFragment(); fragment3 = new ImageFragment(); fragment4 = new ImageFragment(); views.add(fragment2); views.add(fragment3); views.add(fragment4); views.add(fragment); viewpager.setAdapter(new MyAdapter(getSupportFragmentManager())); viewpager.setCurrentItem(0); viewpager.setOnPageChangeListener(new PageChangeLisener()); }
private class MyAdapter extends FragmentPagerAdapter{ private List<Fragment> list_views; public MyAdapter(FragmentManager fm) { super(fm); list_views = views; } @Override public Fragment getItem(int arg0) { return list_views.get(arg0); } @Override public int getCount() { return list_views.size(); } }
以上是关于viewpager的一些代码,没有贴全,像是ImageFragment就特别简单,布局里就是一张图片而已。
下面第二个问题,背景色我们很容易搞定,setBackgroundColor就可以。
然后看第三个问题,并不是所有的滑动处理都要在onTouch里进行,像viewpager,我们完全可以看它的listener
class PageChangeLisener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { } @SuppressLint("NewApi") @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { ArgbEvaluator evaluator = new ArgbEvaluator(); if (position % 2 == 0) { llLayout.setBackgroundColor(0XFF8080FF); int evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFF8080FF,0XFFFF8080); llLayout.setBackgroundColor(evaluate); }else { llLayout.setBackgroundColor(0XFFFF8080); int evaluate = (Integer) evaluator.evaluate(positionOffset, 0XFFFF8080,0XFF8080FF); llLayout.setBackgroundColor(evaluate); } } @Override public void onPageSelected(int arg0) { } }
这是整个颜色控制的核心,先说第三个问题,这里用onPageChangeListener来处理了viewpager的滑动,这里虽然拿不到坐标,但是可以拿到一些对我们来说,很有用的东西,看onPageScrolled方法的第二个参数,这里做实验发现,它向右滑动的时候,取值是[0,1),而向左滑动的时候,取值的(1,0],这完全就是为了让开发者做缩放平移等动画的小助手啊!
然后,注意了,我们考虑第四个问题,我不知道大家是否熟悉属性动画,我首先是在属性动画里写了一个对backgroundColor属性设置改变的一个动画:
@SuppressLint("NewApi") private void setBackRepeat(View view,String property,int from , int to){ ValueAnimator animator = ObjectAnimator.ofInt(view,property,from,to); animator.setDuration(2000); animator.setRepeatMode(ValueAnimator.REVERSE); animator.setRepeatCount(ValueAnimator.INFINITE); animator.setEvaluator(new ArgbEvaluator()); animator.start(); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { // TODO Auto-generated method stub System.out.println("value : "+Integer.toHexString((Integer)animation.getAnimatedValue())); } }); }
然后我打印了动画执行时的颜色的变化,然后我发现他居然会渐变成为你想要的颜色,而不是刷的一下就变了,这下,开心了。
把这个属性动画里的颜色估值器拿出来,ArgbEvaluator,就是它!它的实现特别简单,大家可以点进去看看源码,然后用这个估值器我们来做估值。
首先说说这几个参数,
evaluator.evaluate(positionOffset, 0XFF8080FF,0XFFFF8080);
估值器new出来之后,进行估值,第一个参数是0-1的一个可变参数,0表示开始变化,1表示变化结束,第二个参数是开始的颜色值,第三个参数是结束的颜色值。而这个方法就会一直返回一个在0-1之间过度的颜色值,直到颜色变化完为止。
这样我们就完全可以试想上述效果了!
接着,我们来实现第二个效果!就是在背景色渐变的基础上,再加上滑动渐变!
我们仔细看第二个效果,发现viewpager后面的背景色,原本就是从左上角到右下角渐变的,然后滑动过程中,颜色继续随手指渐变,滑动结束后,左上角和右下角的颜色互换了位置,中间还是渐变色。是不是比第一个效果瞬间又提升了bigger!我们再来实现一下它!
考虑问题:
1.背景色渐变的实现方式?
2.viewpager是否需要自定义?
3.滑动事件的获取?
4.渐变的处理?
我们逐个解决。
第一个,背景渐变,大家熟知的shape,对,一开始我也想到了它,而且想到了属性动画,对backgroundResource的设置,但是很遗憾,背景色没有渐变效果,所以放弃。然后背景色的实现,我简单的自定义了一个view,让这个view做viewpager的背景,来随手指渐变。
第二个,viewpager没有自定义,因为viewpager上没有特别复杂的效果,没有特别绚丽的切换(你完全可以自己加上,github有开源的),所以我没有自定义。
第三个,滑动事件的处理仍然延用了上一个效果的listenr,完全无法舍弃第二个参数offset这个从0-1的小baby啊!
第四个,单纯的颜色估值器无法满足我们的需求,但结合上我们自定义的view就能实现双渐变效果了!
public class MyLinearLayout extends View { private LinearGradient gradinet; private Paint paint; private int width; private int height; private int start = 0XFFFF8080; private int end = 0XFF8080FF; public MyLinearLayout(Context context) { super(context); getDisplay(context); } public MyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); getDisplay(context); } private void getDisplay(Context context) { WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); width = wm.getDefaultDisplay().getWidth(); height = wm.getDefaultDisplay().getHeight(); } public void setGradient(int start,int end){ this.start = start; this.end = end; gradinet = new LinearGradient(0, 0, width, height, start, end, Shader.TileMode.MIRROR); invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); System.out.println("!!!!!!!!!!!!!!!!"); if (paint == null) { paint = new Paint(); } if (gradinet == null) { gradinet = new LinearGradient(0, 0, width, height, start, end, Shader.TileMode.MIRROR); } paint.setShader(gradinet); canvas.drawRect(0, 0, width , height, paint); } }
核心!!就是这么个简单但重要的自定义控件,里面用LinearGradient实现了渐变,在加上估值器,一个双渐变效果就这么出来了!
开源!!这个项目的代码我提交到github上,我衷心并且恳切的希望能有人把viewpager的切换效果也加入到这个项目中,向我发出合并申请。谢谢。
还得提一句,一直想写一系列关于Android动画的博客,但是一直抽不出太多时间(短时间无法写完),demo我已经写完了,所以关于这部分以后博客肯定会有,莫急莫急。