"Open source project resolution" Background with wave effect textview--from Titanic Project Learning Bitmapshader use

Source: Internet
Author: User
Tags transparent color

Hello, long time no article, there is wood to think I ah ~
The formal work has been over the past one months, found in Qingdao internship and work in Beijing, feel completely different ~
Now every night back to live in the place, are tired to sleep ... So also not in the mood to write too many articles and everyone to share, but I will adjust the status as soon as possible, to revitalize the! (where it's weird ...)

        • Project Introduction
        • My thoughts.
        • Implementation ideas

Project Introduction

This article, will introduce an open source project, called Titanic, yes, Chinese name is called "Titanic" ...

Here is the project address
Https://github.com/RomainPiel/Titanic

The effect to be achieved is that the following drops

My thoughts.

If you are a programmer, then at the first sight of this effect, you might think, if I want to achieve a similar effect, what should I do?

I do not know what kind of thinking you will have, when I first saw, I think of Porterduffxfermode, the front is a picture of the text, a picture of a wave behind, and then set the intersection mode, resulting in this text and the image of the cross-effect, constantly changing the position of the back image, Achieve a dynamic effect.

Of course, I just think about it, and then hold the idea to see the source, read the source to find out, the author of the realization of ideas more nb~ through the bitmapshader to achieve this effect, below, I will introduce the source code, to introduce you to realize the idea, very simple, do not blink oh ~

Implementation ideas

Titanic this project is very simple, only two classes, respectively Titanic and Titanictextview, then how to use it? Very simple:

TitanicTextView tv = (TitanicTextView) findViewById(R.id.my_text_view);        tv.setTypeface(Typefaces.get"Satisfy-Regular.ttf"));        new Titanic().start(tv);

If you do not want to set a special font, then the middle of the code can also be deleted, two lines of code to fix, is not very easy~

So what's titanic this class for?

In order to facilitate understanding and watch, I will not important code omitted, you can watch against the source
After we call the start () of Titanic, we execute the following code:

 Public void Start(FinalTitanictextview TextView) {FinalRunnable animate =NewRunnable () {@Override             Public void Run() {textview.setsinking (true);//Horizontal animation. $ = wave.png widthObjectanimator maskxanimator = Objectanimator.offloat (TextView,"Maskx",0, $);                Maskxanimator.setrepeatcount (Valueanimator.infinite); Maskxanimator.setduration ( +); Maskxanimator.setstartdelay (0);inth = textview.getheight ();//Vertical animation                //Masky = 0 Wave vertically centered                //Repeat mode REVERSE to go back and forthObjectanimator maskyanimator = Objectanimator.offloat (TextView,"Masky", h/2,-h/2);                Maskyanimator.setrepeatcount (Valueanimator.infinite);                Maskyanimator.setrepeatmode (Valueanimator.reverse); Maskyanimator.setduration (10000); Maskyanimator.setstartdelay (0);//Now play both animations togetherAnimatorset =NewAnimatorset ();                Animatorset.playtogether (Maskxanimator, maskyanimator); Animatorset.setinterpolator (NewLinearinterpolator ()); Animatorset.addlistener (NewAnimator.animatorlistener () {@Override                     Public void Onanimationstart(Animator animation) {                    }@Override                     Public void Onanimationend(Animator animation) {textview.setsinking (false);if(Build.VERSION.SDK_INT < Build.version_codes.                        Jelly_bean) {textview.postinvalidate (); }Else{textview.postinvalidateonanimation (); } Animatorset =NULL; } omitted ...});if(Animatorlistener! =NULL) {Animatorset.addlistener (Animatorlistener);            } animatorset.start (); }if(!textview.issetup ()) {Textview.setanimationsetupcallback (NewTitanictextview.animationsetupcallback () {@Override                 Public void onsetupanimation(FinalTitanictextview target) {animate.run ();        }            }); }Else{Animate.run (); }        };

Is this code very simple? But it's a little strange, why do we declare runnable objects inside? And there is no thread, but a direct call to run (), a very strange code!

In fact, this does not need to think more, the author is just for the code reuse, the need to put the code in the Run () method, convenient to call, but this code style I do not like, because it will let other people read the code misunderstanding, such as I for this piece of code, think for more than half an hour why he wrote ...

We can't stand it, we can change it to the following way:

 Public void Start(FinalTitanictextview TextView) {if(!textview.issetup ()) {Textview.setanimationsetupcallback (NewTitanictextview.animationsetupcallback () {@Override                 Public void onsetupanimation(FinalTitanictextview target) {run (TextView);        }            }); }Else{Run (TextView); }    }Private void Run(FinalTitanictextview TextView) {textview.setsinking (true); Objectanimator maskxanimator = Objectanimator.offloat (TextView,"Maskx",0, $);        Maskxanimator.setrepeatcount (Valueanimator.infinite); Maskxanimator.setduration ( +); Maskxanimator.setstartdelay (0);inth = textview.getheight (); Objectanimator maskyanimator = Objectanimator.offloat (TextView,"Masky", H/2,-H/2);        Maskyanimator.setrepeatcount (Valueanimator.infinite);        Maskyanimator.setrepeatmode (Valueanimator.reverse); Maskyanimator.setduration (10000); Maskyanimator.setstartdelay (0);//Now play both animations togetherAnimatorset =NewAnimatorset ();        Animatorset.playtogether (Maskxanimator, maskyanimator); Animatorset.setinterpolator (NewLinearinterpolator ()); Animatorset.addlistener (NewAnimator.animatorlistener () {@Override             Public void Onanimationstart(Animator animation) {            }@Override             Public void Onanimationend(Animator animation) {textview.setsinking (false);if(Build.VERSION.SDK_INT < Build.version_codes.                Jelly_bean) {textview.postinvalidate (); }Else{textview.postinvalidateonanimation (); } Animatorset =NULL; }@Override             Public void Onanimationcancel(Animator animation) {            }@Override             Public void onanimationrepeat(Animator animation)        {            }        });    Animatorset.start (); }

It's all about code reuse, and I prefer this code style.
OK, no nonsense, let's see what's going on in Start ()!

TextView. setsinking(true);Objectanimator Maskxanimator = Objectanimator. Offloat(TextView,"Maskx",0, $);Maskxanimator. Setrepeatcount(Valueanimator. INFINITE);Maskxanimator. Setduration( +);Maskxanimator. Setstartdelay(0);int h = TextView. GetHeight();Objectanimator Maskyanimator = Objectanimator. Offloat(TextView,"Masky", H/2,-H/2);Maskyanimator. Setrepeatcount(Valueanimator. INFINITE);Maskyanimator. Setrepeatmode(Valueanimator. REVERSE);Maskyanimator. Setduration(10000);Maskyanimator. Setstartdelay(0);

This code is also very well understood, set a flag bit, indicating that we are going to start sinking ha! And then use two objectanimator to animate, what does this animation control do?

Look inside the parameters, Maskx and Masky, the author's comments written very clearly, maskx range is 0-200,200 is the height of the picture, what picture? Of course, the image of the back wave effect, see (What?) No pictures!? The white can not see ... Right-click Save to see it):

Note that the upper part of this picture is transparent, the white one below, and the width high to 200*300.

Masky Change range is H/2 to-h/2,h is the height of the TextView, that is, the upper and lower floating height of H, then this maskx and Masky exactly what is it, the two properties control what?

First of all, we know that if we want to use objectanimator to achieve this effect, then our control must have the getter and setter of this property, so these two properties are definitely custom, we go to see Titanictextview code validation:

 public      float  getmaskx  () {return  maskx; } public  void   Setmaskx  (float  maskx) {this . maskx = Mas        KX;    Invalidate (); } public  float      Getmasky  () {return  Masky; } public  void   Setmasky  (float  Masky) {this . Masky = Mas        KY;    Invalidate (); }

Sure enough, we see that the author defines the two member variables themselves, so what is the effect of changing the two values? Let's find out where these two values are used in the code:

@Override    protectedvoidonDraw(Canvas canvas) {        ifnull) {            ifnull) {                getPaint().setShader(shader);            }            shaderMatrix.setTranslate(maskX, maskY + offsetY);            shader.setLocalMatrix(shaderMatrix);        else {            getPaint().setShader(null);        }        super.onDraw(canvas);    }

Yes, in OnDraw (), the two parameters were used before Super.ondraw (), there are several variables, we haven't introduced

    • Sinking used to determine whether to start floating animations
    • Shader this is a bitmapshader, this is the hero of our day
    • Shadermatrix This is a transformation matrix, here the main settranslate operation, the parameters are our maskx and Masky and offsety

What is this offsety? Look for it in the code.

private void Createshader () {if (wave = = null) {wave = Getresources (). Getdrawable(R. drawable. Wave);} int wavew = Wave. Getintrinsicwidth();int Waveh = Wave. Getintrinsicheight();Bitmap B = Bitmap. CreateBitmap(Wavew, Waveh, Bitmap. Config. ARGB_8888);Canvas c = new Canvas (b);C. Drawcolor(Getcurrenttextcolor ());Wave. SetBounds(0,0, Wavew, Waveh);Wave. Draw(c);Shader = new Bitmapshader (b, shader. Tilemode. REPEAT, Shader. Tilemode. CLAMP);Getpaint (). Setshader(shader);OffsetY = (getheight ()-Waveh)/2;}

At the end of the calculation of the height of Offsety,textview minus Waveh, and then divided by two, which is actually a wave or B's y-coordinate, on this basis, and then do the following operations, you can achieve the animation effect of moving up and down around

shaderMatrix.setTranslate(maskX, maskY + offsetY);shader.setLocalMatrix(shaderMatrix);

So what does this shader do? Why is it our hero?
In the above code, we can see that not only the offsety is initialized, but also the shader is initialized with three parameters passed in.

New Bitmapshader (b, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);

The first parameter, B, sets the bitmap object to be used by the shader, the second parameter sets the x-axis image extension, and the third parameter is the extension on the y-axis, which has the following three

    • CLAMP: If the renderer exceeds the original boundary range, it replicates the range of edge staining
    • REPEAT: Landscape and portrait Repeat renderer picture, tiled
    • MIRROR: Mirrored mode tiling.

So here's the way we see it, the author repeats on the x-axis and renders the edge color on the y-axis, so the shader that wave gets is the following ()

How Painters ... ^_^

Also note that when creating a Bitmapshader, the first parameter is derived

int wavew = Wave. Getintrinsicwidth();int Waveh = Wave. Getintrinsicheight();Bitmap B = Bitmap. CreateBitmap(Wavew, Waveh, Bitmap. Config. ARGB_8888);Canvas c = new Canvas (b);C. Drawcolor(Getcurrenttextcolor ());Wave. SetBounds(0,0, Wavew, Waveh);Wave. Draw(c);Shader = new Bitmapshader (b, shader. Tilemode. REPEAT, Shader. Tilemode. CLAMP);

First, according to Wave's drawable object's length and width, build a bitmap object of the same size, then go to create a canvas object, and then draw a background with the current text color, when we shader the above transparent color, it becomes our text color, Then to drawable set bounds, draw a bit, so that our bitmap object, is a wave with the drawable of the same size, the lower part is a white wave, the upper part is a text color background of a picture, This time when creating a bitmapshader, you can get what we want, and then

 getPaint().setShader(shader);

Set to paint, so the word written in this pen, is the word we created a good bitmapshader for the background ~

What about the wave effect?

After opening the animation, change maskx and Masky, and then use the matrix to move the position of the Bitmapshader, the font background color changes slightly, and we see the effect is the wave effect ~

Do you remember the range of changes in Masky?

H/2 to-H/2

This will be able to get from the bottom without the waves, has been growing to the white waves covered with the entire height, and then this effect will appear ~

OK, this article is written here, next time we see, go home to see the journey to the Monkey

Reprint Please specify source: http://blog.csdn.net/zhaokaiqiang1992

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

"Open source project resolution" Background with wave effect textview--from Titanic Project Learning Bitmapshader use

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.