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