It looks like a lot of work.
Later, I was thinking, since the web side can add a gray effect to the whole page, should our app also be ok?
How do we add a grayscale effect to the app page?
Under normal circumstances, our app page is actually drawn by Canvas, right?
The corresponding API of Canvas must also support grayscale.
So is it OK for us to set a grayscale effect before drawing the control, such as drawing?
Seems to have found something mysterious.
1. Try to give ImageView a grayscale effect
Then we first verify the feasibility of gray effect through ImageView.
We write a custom ImageView called GrayImageView
The layout file is as follows:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".TestActivity"> <ImageView android:layout_width="100dp" android:layout_height="wrap_content" android:src="@mipmap/logo"> </ImageView> <com.imooc.imooc_wechat_app.view.GrayImageView android:layout_width="100dp" android:layout_height="wrap_content" android:src="@mipmap/logo" /> </LinearLayout>
Very simple. We put an ImageView for comparison.
Take a look at the code of GrayImageView:
public class GrayImageView extends AppCompatImageView { private Paint mPaint = new Paint(); public GrayImageView(Context context, AttributeSet attrs) { super(context, attrs); ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0); mPaint.setColorFilter(new ColorMatrixColorFilter(cm)); } @Override public void draw(Canvas canvas) { canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG); super.draw(canvas); canvas.restore(); } }
Before analyzing the code, let's take a look at the rendering:
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-nz0w2uy2-1630841092587)( https://user-gold-cdn.xitu.io/2020/4/4/171458144c8df964? imageView2/0/w/1280/h/960/ignore-error/1)]
It's perfect. We successfully made the WAN Android icon gray.
Take a look at the code. The code is very simple. We copied the draw method and made a special treatment for canvas in this method.
What special treatment? In fact, a grayscale effect is set.
In the App, we often use the color matrix for color processing, which is a 4 * 5 matrix. The principle is as follows:
[ a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t ]
When applied to a specific color [R, G, B, A], the final color is calculated as follows:
R' = a*R + b*G + c*B + d*A + e; G' = f*R + g*G + h*B + i*A + j; B' = k*R + l*G + m*B + n*A + o; A' = p*R + q*G + r*B + s*A + t;
Does it look bad? Yes, I feel bad too. I'm annoyed when I see algebra.
Since everyone is uncomfortable, Android is more considerate. It gives us a ColorMatrix class. This class provides many APIs. You can call the API directly to get most of the desired effects. Unless you have special operations, you can calculate by yourself through the matrix.
For effects such as grayscale, we can operate through the saturation API:
setSaturation(float sat)
Just pass in 0. Look at the source code. A specific matrix is passed in at the bottom to do the operation.
ok, well, forget the above, just remember that you have an API that can make the things drawn by canvas gray.
So we have implemented the grayscale of ImageView. Can TextView? Button OK?
2. Try to draw inferences from one instance
Let's try TextView and Button.
The code is exactly the same. In fact, it is to change an implementation class, such as GrayTextView:
public class GrayTextView extends AppCompatTextView { private Paint mPaint = new Paint(); public GrayTextView(Context context, AttributeSet attrs) { super(context, attrs); ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0); mPaint.setColorFilter(new ColorMatrixColorFilter(cm)); } @Override public void draw(Canvas canvas) { canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG); super.draw(canvas); canvas.restore(); } }
There is no difference. The GrayButton will not be pasted. Let's look at the layout file:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".TestActivity"> <ImageView android:layout_width="100dp" android:layout_height="wrap_content" android:src="@mipmap/logo"> </ImageView> <com.imooc.imooc_wechat_app.view.GrayImageView android:layout_width="100dp" android:layout_height="wrap_content" android:src="@mipmap/logo" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hongyang is so handsome" android:textColor="@android:color/holo_red_light" android:textSize="30dp" /> <com.imooc.imooc_wechat_app.view.GrayTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hongyang is so handsome" android:textColor="@android:color/holo_red_light" android:textSize="30dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hongyang is so handsome" android:textColor="@android:color/holo_red_light" android:textSize="30dp" /> <com.imooc.imooc_wechat_app.view.GrayButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hongyang is so handsome" android:textColor="@android:color/holo_red_light" android:textSize="30dp" /> </LinearLayout>
Corresponding renderings:
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (img-mj5prr0t-1630841092589)( https://user-gold-cdn.xitu.io/2020/4/4/1714581a54b2a078? imageView2/0/w/1280/h/960/ignore-error/1)]
You can see that TextView and Button also successfully changed the red font to gray.
Do you suddenly feel that you will?
In fact, we just need to replace various related views with this custom View and use appcompat to change the skin. There is no need for the Server to participate, and the client can make fun of it.
Is it? Do we need to replace all views with custom views?
It sounds expensive, too.
Think again, is there anything simpler?
3. Look up
Although the layout file just now is very simple, I invite you to have a look at the layout file just now. I want to ask you a question:
Watch it.
- Who is the parent View of ImageView in the above xml?
- Who is the parent View of TextView?
- Who is the parent View of the Button?
Do you have any enlightenment!
Do we need to customize one by one?
The parent views are LinearLayout. Let's make a GrayLinearLayout. The internal views will turn gray. After all, the Canvas object is passed down.
Let's try:
GrayLinearLayout:
public class GrayLinearLayout extends LinearLayout { private Paint mPaint = new Paint(); public GrayLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); ColorMatrix cm = new ColorMatrix(); cm.setSaturation(0); mPaint.setColorFilter(new ColorMatrixColorFilter(cm)); } @Override public void draw(Canvas canvas) { canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG); super.draw(canvas); canvas.restore(); } @Override protected void dispatchDraw(Canvas canvas) { canvas.saveLayer(null, mPaint, Canvas.ALL_SAVE_FLAG); super.dispatchDraw(canvas); canvas.restore(); } }
The code is very simple, but pay attention to one detail. We also copied dispatchDraw. Why? Think for yourself:
Let's replace the following xml:
<?xml version="1.0" encoding="utf-8"?> <com.imooc.imooc_wechat_app.view.GrayLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".TestActivity"> <ImageView android:layout_width="100dp" android:layout_height="wrap_content" android:src="@mipmap/logo" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hongyang is so handsome" android:textColor="@android:color/holo_red_light" android:textSize="30dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hongyang is so handsome" android:textColor="@android:color/holo_red_light" android:textSize="30dp" /> </com.imooc.imooc_wechat_app.view.GrayLinearLayout>
We put the ImageView with blue Logo, TextView and Button with red font to see the effect:
[external chain picture transfer failed. The source station may have anti-theft chain mechanism. It is recommended to save the picture and upload it directly (IMG ulziiqvr-1630841092590)( https://user-gold-cdn.xitu.io/2020/4/4/1714581d299f522b?imageView2/0/w/1280/h/960/ignore -error/1)]
Perfect!
Isn't it a little enlightened again!
As long as we change the root layout of the Activity we set!
The root layout of an Activity may be LinearLayout,FrameLayout,RelativeLayout,ConstraintLayout
Change the chicken... When does it have to be changed? What's the difference between it and just now.
Any ideas? Nothing definite?
Think again.
Where will the root layout of our set Activity be placed?
android.id.content
Is it on this Content View?
This content view has always been FrameLayout!
Then we just need to generate the FrameLayout corresponding to android.id.content and replace it with GrayFrameLayout.
How?
appcompat? Go to LayoutFactory?
It's OK, but if you want to set LayoutFactory, you need to consider the logic related to appcompat.
Is there a scheme that doesn't need to modify any process?
4. Details in layoutinflator
There are.
Our AppCompatActivity can duplicate the onCreateView method. In fact, this method is also called back by LayoutFactory when building the View, which generally corresponds to its internal mPrivateFactory.
His priority is lower than that of Factory and Factory2. Relevant codes:
if (mFactory2 != null) { view = mFactory2.onCreateView(parent, name, context, attrs); } else if (mFactory != null) { view = mFactory.onCreateView(name, context, attrs); } else { view = null; } if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, context, attrs); } if (view == null) { final Object lastContext = mConstructorArgs[0]; mConstructorArgs[0] = context; try { if (-1 == name.indexOf('.')) { view = onCreateView(parent, name, attrs); } else { view = createView(name, null, attrs); } ### **Write at the end** Finally, I want to say: for programmers, there are too many knowledge contents and technologies to learn. If they want not to be eliminated by the environment, they have to constantly improve themselves,**It is always us to adapt to the environment, not the environment to adapt to us!** Dozens of sets related to the above technical system diagram are attached here**Interview questions of Tencent, headlines, Alibaba, meituan and other companies in 2021**,Organize the technical points into videos and PDF(It actually took a lot more effort than expected), including**Knowledge Vein + Many details**,Due to the limited space, some of them are shown here in the form of pictures. **I believe it will bring you a lot of harvest:** ![](https://img-blog.csdnimg.cn/img_convert/156e962cc5d7e78521796127e5b4cfd8.png) ![](https://img-blog.csdnimg.cn/img_convert/2299a1b4b372d7c61d8785b5309b82f5.png) **[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://codechina.csdn.net/m0_60958482/android_p7)** If you are not eliminated by the environment, you have to constantly improve yourself,**It is always us to adapt to the environment, not the environment to adapt to us!** Dozens of sets related to the above technical system diagram are attached here**Interview questions of Tencent, headlines, Alibaba, meituan and other companies in 2021**,Organize the technical points into videos and PDF(It actually took a lot more effort than expected), including**Knowledge Vein + Many details**,Due to the limited space, some of them are shown here in the form of pictures. **I believe it will bring you a lot of harvest:** [External chain picture transfer...(img-6eMp7Gtl-1630841092592)] [External chain picture transfer...(img-fTUgRKDR-1630841092596)] **[CodeChina Open source projects:< Android Summary of study notes+Mobile architecture video+Real interview questions for large factories+Project practice source code](https://codechina.csdn.net/m0_60958482/android_p7)** > It's easy to be a programmer. Being an excellent programmer requires continuous learning. From junior programmer to senior programmer, from junior architect to senior architect, or to management, from technical manager to technical director, each stage needs to master different abilities. Determine your career direction early in order to get rid of your peers in work and ability improvement.