Android custom controls-3D galleries and image matrices
1.3D gallery implementation
We know that the android system has provided us with a "Container" for displaying images-Gallery. However, this Gallery shows flat effects and does not have a strong dynamic effect. Here, we are working on a custom Gallery component to display the 3D effects of images. Think about it. Let's take a look:
What should I do with Gallery that achieves this 3D effect? First, analyze,
1. display the image. The system comes with the Gallery component, which can be used to expand the effect we need.
2. 3D imaging is required for the presentation.
3. The image reflection must be displayed below the image.
4. Apply a "Mask" to the image reflection.
Okay, the problem is listed. Let's solve it one by one! The amount of code is small, and the code is ready directly.
Package com. example. gallery. view; import android. content. context; import android. graphics. camera; import android. graphics. matrix; import android. util. attributeSet; import android. view. view; import android. view. animation. transformation; import android. widget. gallery; import android. widget. imageView; @ SuppressWarnings (deprecation) public class CustomGallery extends Gallery {/** center point of the Gallery */private int galler YCenterPoint = 0;/** Camera object */private camera Camera; public CustomGallery (Context context, AttributeSet attrs) {super (context, attrs); // start getChildStaticTransformationsetStaticTransformationsEnabled (true ); camera = new Camera ();}/*** calls back this method when the width and height of Gallery change. When the width and height of gallery are calculated for the first time, this method is also called */@ Overrideprotected void onSizeChanged (int w, int h, int oldw, int oldh) {// TODO Auto-generated method stubsuper. onSize Changed (w, h, oldw, oldh); galleryCenterPoint = getGalleryCenterPoint ();} /*** return the transform effect of the child image of the gallery item ** @ param t * specify the transform effect of the current item */@ Overrideprotected boolean getChildStaticTransformation (View child, Transformation t) {int viewCenterPoint = getViewCenterPoint (child); // the center point of the view int rotateAngle = 0; // The rotation angle. The default value is 0. // if the center point of the view is not equal to the gallery center, the image on both sides needs to calculate the rotation angle if (viewCenterPoint! = GalleryCenterPoint) {// gallery center point-view center point = difference int diff = galleryCenterPoint-viewCenterPoint; // difference value/image width = ratio float scale = (float) diff/(float) child. getWidth (); // ratio * Maximum Rotation Angle = Rotation Angle of the final view (the maximum rotation angle is set to 50 degrees) rotateAngle = (int) (scale * 50); if (Math. abs (rotateAngle)> 50) {// when the final rotation angle, change the Maximum Rotation Angle to 50 or-50 rotateAngle = rotateAngle> 0? 50:-50 ;}// before setting the transform effect, you need to clear the transform effect of the previous item in Transformation t. clear (); t. setTransformationType (Transformation. TYPE_MATRIX); // set the transformation effect type to Matrix Type startTransformationItem (ImageView) child, rotateAngle, t); return true ;} /*** set the transform effect ** @ param iv * gallery item * @ param rotateAngle * Rotation Angle * @ param t * transformed object */private void startTransformationItem (ImageView iv, int rotateAngle, Transformation t) {camera. save (); // save status int absRotateAngle = Math. abs (rotateAngle); // 1. zoom in (the middle picture is bigger than the two sides) camera. translate (0, 0, 100f); // locate the camera int zoom =-250 + (absRotateAngle * 2); camera. translate (0, 0, zoom); // 2. transparency (the middle picture is completely displayed, with a certain degree of transparency on both sides) int alpha = (int) (255-(absRotateAngle * 2.5); iv. setAlpha (alpha); // 3. rotate (the image in the middle has no rotation angle, as long as the image in the middle has a rotation angle) camera. rotateY (rotateAngle); Matrix matrix = t. getMatrix (); // transformation matrix, which adds the transformation effect to the Matrix camera. getMatrix (matrix); // returns the matrix to the camera object. The camera object converts the previously added effect into a matrix and adds it to the matrix object. preTranslate (-iv. getWidth ()/2,-iv. getHeight ()/2); // multiply matrix before matrix. postTranslate (iv. getWidth ()/2, iv. getHeight ()/2); // After the matrix, multiply by camera. restore (); // restore the saved status}/*** obtain the center point of the Gallery ** @ return */private int getGalleryCenterPoint () {return this. getWidth ()/2;}/*** get the center of the view on the item ** @ param v * @ return */private int getViewCenterPoint (View v) {return v. getWidth ()/2 + v. getLeft (); // half the image width + left margin of the image from the screen }}
There are comments in the code. You can look at the comments to understand the code. I would like to explain how to think about it here, which is especially troublesome! There is also a very important concept-matrix. I will explain it later.
Tool class for retrieving images:
Package com. example. gallery. view; import java. lang. ref. softReference; import java. util. hashtable; import android. content. res. resources; import android. graphics. bitmap; import android. graphics. bitmap. config; import android. graphics. porterDuff. mode; import android. graphics. porterduxfermode; import android. graphics. shader. tileMode; import android. graphics. bitmapFactory; import android. graphics. canvas; import android. graphics. linearGradient; import android. graphics. matrix; import android. graphics. paint; import android. util. log; public class ImageUtil {private static final String TAG = ImageUtil;/** cache Set */private static Hashtable
> MImageCache // = new Hashtable
> ();/*** Return a processed image by id ** @ param res * @ param resID * @ return */public static Bitmap getImageBitmap (Resources res, int resID) {// check whether the current resID has taken the image in the Set first. If there is an image in the Set, it indicates that it has been taken. Use the image in the set to return SoftReference.
Reference = mImageCache. get (resID); if (reference! = Null) {Bitmap bitmap = reference. get (); if (bitmap! = Null) {// retrieve Log from memory. I (TAG, retrieved from memory); return bitmap ;}// if the collection does not exist, call getInvertImage to get an image. You need to reserve one for the set, finally, the current image Log is returned. I (TAG, reload); Bitmap invertBitmap = getInvertBitmap (res, resID); // save a copy in the set so that you can obtain mImageCache directly in the set next time. put (resID, new SoftReference
(InvertBitmap); return invertBitmap;}/*** Based on the image id, get the processed image ** @ param resID * @ return */public static Bitmap getInvertBitmap (Resources res, int resID) {// 1. obtain the source image Bitmap sourceBitmap = BitmapFactory. decodeResource (res, resID); // 2. generate the reflected image Matrix m = new Matrix (); // image Matrix m. setScale (1.0f,-1.0f); // Let the image reverse by matrix Bitmap invertBitmap = Bitmap. createBitmap (sourceBitmap, 0, sourceBitmap. getHeight ()/2, sourceBitmap. getWidth (), sourceBitmap. getHeight ()/2, m, false); // 3. two images are merged into one image. Bitmap resultBitmap = Bitmap. createBitmap (sourceBitmap. getWidth (), (int) (sourceBitmap. getHeight () * 1.5 + 5), Config. ARGB_8888); Canvas canvas = new Canvas (resultBitmap); // specify a canvas for the merged image. drawBitmap (sourceBitmap, 0f, 0f, null); // draw the original image above the canvas. drawBitmap (invertBitmap, 0f, sourceBitmap. getHeight () + 5, null); // draw the reflected image below the canvas // 4. add the mask effect Paint paint = new Paint (); // set the mask color. Here the linear gradient LinearGradient shader = new LinearGradient (0, sourceBitmap. getHeight () + 5, 0, resultBitmap. getHeight (), 0x70ffffff, 0x00ffffff, TileMode. CLAMP); paint. setShader (shader); // set the mode to: mask, and take the intersection paint. setXfermode (new porterduduxfermode (Mode. DST_IN); canvas. drawRect (0, sourceBitmap. getHeight () + 5, sourceBitmap. getWidth (), resultBitmap. getHeight (), paint); return resultBitmap ;}}
This tool class is used to obtain the entire image, including the reflection and mask effects of the image! Here, we need to explain that it is a complicated concept to avoid OOM. We can make it clear without a sentence or two. It is easy to process OOM when loading images in android. Of course, there are many ways to avoid OOM. I have used the memory cache mechanism to avoid it, that is, using Java to provide us with a good "soft reference" to solve the problem. Next, let's see how to reference this gallery component.
Package com. example. gallery; import com. example. gallery. view. customGallery; import com. example. gallery. view. imageUtil; import android. app. activity; import android. graphics. bitmap; import android. graphics. drawable. bitmapDrawable; import android. OS. bundle; import android. view. view; import android. view. viewGroup; import android. widget. baseAdapter; import android. widget. gallery. layoutParams; import android. widget. ImageView; public class MainActivity extends Activity {/** image resource array */private int [] imageResIDs; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main); imageResIDs = new int [] {// R. drawable. imgres_01, // R. drawable. imgres_02, // R. drawable. imgres_03, // R. drawable. imgres_04, // R. drawable. imgres_05, // R. drawable. imgres_06, // R. Drawable. imgres_07, // R. drawable. imgres_08, // R. drawable. imgres_01, // R. drawable. imgres_02, // R. drawable. imgres_03, // R. drawable. imgres_04, // R. drawable. imgres_05, // R. drawable. imgres_06, // R. drawable. imgres_07, // R. drawable. imgres_08 //}; CustomGallery customGallery = (CustomGallery) findViewById (R. id. customgallery); ImageAdapter adapter = new ImageAdapter (); customGallery. setAdapter (adapter);} publ Ic class ImageAdapter extends BaseAdapter {@ Overridepublic int getCount () {// TODO Auto-generated method stubreturn imageResIDs. length ;}@ Overridepublic Object getItem (int position) {// TODO Auto-generated method stubreturn imageResIDs [position] ;}@ Overridepublic long getItemId (int position) {// TODO Auto-generated method stubreturn position;} @ Overridepublic View getView (int position, View convertVi Ew, ViewGroup parent) {// TODO Auto-generated method stubImageView imageView; if (convertView! = Null) {imageView = (ImageView) convertView;} else {imageView = new ImageView (MainActivity. this);} Bitmap bitmap = ImageUtil. getImageBitmap (getResources (), imageResIDs [position]); BitmapDrawable drawable = new BitmapDrawable (bitmap); drawable. setAntiAlias (true); // remove the Image view with a sawtooth image. setImageDrawable (drawable); LayoutParams params = new LayoutParams (240,320); imageView. setLayoutParams (params); return imageView ;}}}
========================================================== ==== Gorgeous split line ========================================== ==============
2. Android matrix Basics
During the UI development process, we often need to process images, such as textures, complicated ones such as location conversion, rotation, and filter effects, the following describes some basic knowledge and principles of image processing.
1. Basic Concepts
For image processing, the most commonly used data structure is Bitmap, which contains all the data of an image. What content does the data include? In short, it is composed of dot matrix and color value. The so-called dot matrix is a matrix of Width * Height. Each element corresponds to a pixel of the image. That is to say, the dot matrix stores the space location information of the image. The color value is ARGB, which corresponds to the four channels of transparency, red, green, and blue. Each channel is defined in 8 bits, therefore, a color value is an int integer that can represent 256*256*256 color values.
In Android, we often use the following constants: ARGB_8888, ARGB_4444, and RGB_565. These constants tell the system how to process the color value of the image. For example, ARGB_8888 tells the system transparency, R, G, and B that they are represented in 8 bits, at this time, the color value is 32bit. This definition can represent the most color value, and the image quality is also the best. ARGB_4444 indicates that each channel uses 4 bits, so that the color value is only 16 bits, it saves space, but can only represent 16*16*16 colors. That is to say, the image loses a lot of color information. The RGB_565 color value is also 16bit, But it discards the transparency information, it can be 32*64*32 color values.
2 color matrix
A color matrix is a 5*4 matrix used to process the color values of an image. Define the color matrix and color values as follows:
Perform the following matrix operations:
The result is a 4*1 matrix, which is a new color value. The values of each channel in R are 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;
This may seem abstract, and it is difficult to understand the direct relationship between the color matrix and result R. We assume that the color matrix value is as follows:
The result is:
R' = R;
G' = G;
B '= B;
A' =;
That is to say, the new color value is the same as the original one! Let's look at another example. The color matrix value is:
Result:
R' = R + 100;
G' = G + 100;
B '= B;
A' =;
In the new color value, the value of the red channel and the value of the green channel increase by 100, respectively, and the image will become Yellow (because R + G = Yellow ).
From the above examples, we can easily understand the meaning of each component in the color matrix (each column:
The first line is red,
The second line determines green,
The third line determines the blue,
The fourth row determines the transparency,
The Fifth Column is the offset of the color.
So far, we should be able to understand how to change each component of the color value through the color matrix.
The following is a piece of code for Android, which is used to process an image as a yellow image:
public static Bitmap testBitmap(Bitmap bitmap){ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.RGB_565); Canvas canvas = new Canvas(output); Paint paint = new Paint(); ColorMatrix cm = new ColorMatrix(); float[] array = {1,0,0,0,100, 0,1,0,0,100, 0,0,1,0,0, 0,0,0,1,0}; cm.set(array); paint.setColorFilter(new ColorMatrixColorFilter(cm)); canvas.drawBitmap(bitmap, 0, 0, paint); return output; }
3. Coordinate Transformation Matrix
In addition to color value processing, the most common operations on images are spatial coordinate transformation. Common effects include translation, rotation, and stretching, this is actually done through a matrix. A coordinate transformation matrix is a 3*3 matrix. It is a matrix multiplication operation similar to a coordinate value (X, Y, 1, this coordinate value can be converted into a new coordinate value. The calculation process is as follows:
Result:
X' = a * x + B * y + c
Y' = d * x + e * y + f
Like the color matrix, if the coordinate transformation matrix is as follows, the new coordinate values X and Y increase by 50, that is, the distance (50, 50) is shifted for each point of the image, that is, the image is moved to the coordinates (50, 50.
If the coordinate transformation matrix is as follows, all X and Y coordinates are increased by two times, that is, the image is enlarged by two times. Other scaling effects are similar.
What's more complex is the rotation effect. A Rotation Transformation Matrix is as follows:
The result is x' = xcos θ-ysin θ and y' = xsin θ + ycos θ. The effect of this result is to rotate the θ angle counterclockwise around the origin.
The following is a sample code for Android, which is used to translate an image, that is, the cropping effect. For other effects, see the corresponding coordinate transformation matrix:
public static Bitmap test1Bitmap(Bitmap bitmap){ Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.RGB_565); Canvas canvas = new Canvas(output); Paint paint = new Paint(); Matrix cm = new Matrix(); float[] array = {1,0,50, 0,1,50, 0,0,1}; cm.setValues(array); canvas.drawBitmap(bitmap, cm, paint); return output; }
The following describes several commonly used transformation matrices:
1. Rotate
The conversion formula of the θ degrees angle clockwise around the origin point is x' = xcos θ −ysin θ and y' = xsin θ + ycos θ.
2. Zoom
After the conversion, the length and width are enlarged to x' = scale * x; y' = scale * y.
3. Shear
4. Reflection
5. Positive projection
Android's image matrix is definitely more than that. This is a complicated knowledge that involves university-related Mathematics Courses and can understand the matrix knowledge in college linear algebra, it is very helpful for learning the image matrix in Android. I only gave a simple basic explanation, which is understandable and usable. If you want to study it in depth, please refer to the link below to download the information I uploaded to the CSDN resource library today.
Android image matrix basics and detailed information
Download the source code here