This is an English translation of the provided Chinese text:
8.3.6 Paint API — Xfermode and PorterDuff Detailed Explanation (Part Three)
Category Android Basic Tutorial
Introduction to This Section:
>
In the previous section, we studied the third child of Xfermode: PorterDuffXfermode, which has a single parameter in its constructor: PorterDuff.Mode. After observing 16 image blending modes, we also wrote code to verify the 18 different blending modes documented, with 18 being the addition of ADD and OVERLAY modes! Of course, merely verifying is not enough; in this section, we will write an example to help us become familiar with how to use the blending modes provided by PorterDuff.Mode in practice! The example in this section is the implementation of circular and rounded-corner shapes!
In 2.3.4 ImageView (Image View), we explained the simplest implementation of a circular ImageView, which is based on the principle of calling clipPath to cut out a circle from the image!
This section, however, uses the DST_IN mode in PorterDuff.Mode to achieve the effect. Without further ado, let's start the content of this section! PS: The example in this section is taken from Hong Yang's great work — Android Xfermode Practical Implementation of Circular and Rounded Images. In addition, we still need to post the effect diagram of PorterDuff.Mode:
1. The Effect Diagram and Implementation Process Analysis to be Achieved:
The effect diagram after running :
Well, the above is the effect we want to achieve, through this PorterDuff.Mode.DST_IN mode! Let's analyze the implementation process:
>
Step 1: Xfermode is nothing more than two layers of images. The one drawn first is called the DST image (the target image), and the one drawn later is called the SRC image (the original image). To achieve a circle or a rounded corner, we can first draw out the image to be displayed (DST), where we set it through the properties of src; Then, draw the circle and rounded corners (SRC). The part we want to display is where they intersect, and it is the content of the image part, so we choose the DST_IN mode!
Step 2: Well, knowing the principle, let's consider the issues related to the custom ImageView next:
We want the View we draw to be rounded or circular, so we need to add an attribute to determine it, and the rounded corner also needs a radius parameter, so we can take out these parameters through the custom attribute (attrs.xml), and then in the custom View's constructor, take out these parameters!
Then it's time to calculate the size of the image: First, if we set it to a circle, we need to make the width and height consistent, based on the smaller value. We can call getMeasuredXxx() in the onMesure() method to get the width and height, and see which one is smaller, and call setMeasuredDimension(x, x) to set the width and height! Then, in the onDraw() method, we get the width and height of the image, and then according to the image width and height, as well as the View width and height, calculate the scaling ratio. If the image width and height do not match the View's width and height, the resulting image width and height must be greater than the View's width and height, so take the larger value!
Next, it's time to draw the image. Define a method for drawing shapes, and then initialize the paintbrush, set setXfermode to PorterDuff.Mode.DST_IN, draw the image first, and then draw the shape.
Finally, it's about the image cache. Here, a WeakReference is used to cache the image to avoid allocating memory and redrawing every time onDraw is called. Finally, clear the cache in invalidate!
The general implementation process is as described above. Knowing the process makes it much easier to look at the code!
2. Code Implementation:
Custom control attribute: res/attrs.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CircleImageView">
<attr name="Radius" format="dimension"/>
<attr name="type">
<enum name="circle" value="0"/>
<enum name="round" value="1"/>
</attr>
</declare-styleable>
</resources
mWeakBitmap = new WeakReference<Bitmap>(bitmap);
// Draw the image
canvas.drawBitmap(bitmap, 0, 0, null);
mPaint.setXfermode(null);
}
if (bitmap != null) {
mPaint.setXfermode(null);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, mPaint);
return;
}
}
// Cache Bitmap to avoid reallocating memory and redrawing every OnDraw
@Override
public void invalidate() {
mWeakBitmap = null;
if (mWeakBitmap != null) {
mMaskBitmap.recycle();
mMaskBitmap = null;
}
super.invalidate();
}
// Define a method for drawing shapes
private Bitmap getBitmap() {
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); // Anti-aliasing
paint.setColor(Color.BLACK);
if (type == TYPE_ROUND) {
canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()),
mBorderRadius, mBorderRadius, paint);
} else {
canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint);
}
return bitmap;
}
}
Finally, call it in the layout file: **activity_main.xml** :
```xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.jay.xfermodedemo1.CircleImageView
android:layout_width="160dp"
android:layout_height="240dp"
android:layout_margin="10dp"
android:src="@mipmap/ic_bg_meizi2"
app:type="circle" />
<com.jay.xfermodedemo1.CircleImageView
android:layout_width="160dp"
android:layout_height="280dp"
android:layout_margin="10dp"
android:src="@mipmap/ic_bg_meizi1"
app:Radius="30dp"
app:type="round" />
</LinearLayout>
Well, if you can't understand the code at first glance, you will after a few more looks~
3. Download this section's code example:
Summary of this section:
>
In this section, we discussed the first application example of Xfermode and PorterDuff, setting the DST_IN mode to achieve custom ImageViews for circular and rounded corner images. I believe everyone has a basic understanding of the simple application of PorterDuff. Strike while the iron is hot, and in the next section, we will write an example to practice together~ Alright, that's all for now, thank you~
-1.0 Android Basic Tutorial Introduction
-1.0.1 Latest Android Basic Tutorial Catalog for 2015
-1.1 Background and System Architecture Analysis
-1.2 Development Environment Setup
-1.2.1 Developing Android APPs with Eclipse + ADT + SDK
-1.2.2 Developing Android APPs with Android Studio
-1.3 Solving SDK Update Issues
-1.4 Genymotion Emulator Installation
-1.5.1 Git Tutorial on Basic Operations of Local Repositories
-1.5.2 Git: Using GitHub to Set Up a Remote Repository
-1.6 How to Play with 9-patch Images
-1.7 Interface Prototype Design
-1.8 Project-Related Analysis (Various Files, Resource Access)
-1.9 Android Program Signing and Packaging
-1.11 Decompiling APK to Retrieve Code & Resources
-2.1 The Concept of View and ViewGroup
-[2.2.1 LinearLayout (Linear Layout)](android-tutorial-linearlayout
2.5.4 Basic Usage of AutoCompleteTextView (Auto-Complete Text Box)
2.5.8 Detailed Explanation of Notification (Status Bar Notification)
2.6.4 Simple Usage of DrawerLayout (Official Side-Slide Menu)
3.6 Responding to System Setting Events (Configuration Class)
4.4.2 Further Exploration of ContentProvider - Document Provider
5.2.1 Detailed Explanation of Fragment Example - Implementation of Bottom Navigation Bar (Method 1)
5.2.2 Detailed Explanation of Fragment Example - Implementation of Bottom Navigation Bar (Method 2)
5.2.3 Detailed Explanation of Fragment Example - Implementation of Bottom Navigation Bar (Method 3)
5.2.4 Detailed Explanation of Fragment Example - Bottom Navigation Bar + ViewPager Page Switching
6.2 Data Storage and Access - SharedPreferences for Saving User Preferences
7.1.1 What to Learn in Android Network Programming and Http Protocol Study
[7.1.2 Learning about Android Http Request and Response Headers](android-tutorial-http
8.3.14 Paint API - Several Enumerations/Constant Values and ShadowLayer Shadow Effect
8.3.17 Detailed Explanation of Canvas API (Part 2) - Collection of Clipping Methods
8.3.18 Detailed Explanation of Canvas API (Part 3) - Matrix and drawBitmapMesh
8.4.3 Android Animation Collection - Property Animation - First Encounter
8.4.4 Android Animation Collection - Property Animation - Another Encounter
11.0 "2015 Latest Android Basic Tutorial" Concludes with Cheers~
12.2 DrySister Girl Viewing App (First Edition) - 2. Parsing Backend Data
12.4 DrySister Girl Viewing App (First Edition) - 4. Adding Data Caching (Integrating SQLite)