Customize an imageview control that can dynamically mask any image and mask the imageview.

Source: Internet
Author: User

Customize an imageview control that can dynamically mask any image and mask the imageview.
Customize an imageview control that can dynamically mask any image

The company's project requirements are similar to the Development of nail apps. After you select a different type of a image, you need to convert the imageview control that stores your fingers on the interface into the shape selected by the user, this requirement was quite big at the time. I did not sit on a custom control like this before, so I searched Goole.

What I said in my blog is indeed quite good. The entire custom process and steps are very clear. A demo is available for download in the blog, so I downloaded a trial. After running the demo, I felt quite good. I was glad to find the problem, this custom control must put the drawable of the image to be masked in the xml layout in the form of resid, which is not flexible, I cannot meet the needs of changing various shapes with flexible user operations. However, this is a solution that has been found for a long time and there is no better solution. What should I do?

Don't always want to get ready-made. Use your own brains to customize it, so you can find the idea of re-development based on the idea of the original master, the original method of the blogger is to use the constructor of the three parameters of the custom view to transfer the resource id of the custom shape image, in the onmeasure method, bitmap is generated based on the image resource id to obtain and record the corresponding path object. I want to dynamically set the mask shape of this imageview in two ways, one is the resource id of the image, and the other is the bitmap object of an image, which can achieve the effect of the image shape provided by the mask, we usually use the setImageresouse () method and setImageBitamp () method open to our Android system to dynamically change the requirement of the imageview control to display objects in the code, can I simply rewrite the two methods of imageView? In this way, the resources of the masked image can be dynamically changed, regardless of the id or bitamp object, after the User-Defined attempt is successful, the code for these two methods is attached below:

@Override    public void setImageResource(@DrawableRes int resId) {        super.setImageResource(resId);        if( lastResId!=0){            if( lastResId == resId){                isReplayRes = false ;            }else {                isReplayRes = true ;            }        }        BitmapFactory.Options options = new BitmapFactory.Options();        options.inJustDecodeBounds = false;         shapeLayerBitmap = getBitmapFromDrawable(shapeLayerDrawable);        showLayerBitmap = getYsSuoBitmap(resId);        resouseBitmap = showLayerBitmap;//        showLayerBitmap = BitmapFactory.decodeResource(context.getResources(),resId,options);//        resouseBitmap = BitmapFactory.decodeResource(context.getResources(),resId,options);//        bitmap = createImage();        lastResId = resId;        postInvalidate();    }    @Override    public void setImageBitmap(Bitmap bm) {        super.setImageBitmap(bm);        this.showLayerBitmap = bm;        isReplayRes =false;        this.resouseBitmap = bm;//        bitmap = createImage();    }

In this way, the problem of dynamically setting the mask image resources is solved, but then a new problem arises. It is found that when the mask is large, the top and bottom of the image are not displayed completely, when I was a child, it was not very obvious, but our project had a finger fine-tuning function. When the test sister clicked fine-tuning, she immediately shouted. Why is this not all displayed, and there were stripes in the middle. I looked at it. Well, I encountered a brain burning problem. Why did this happen? After asking a lot of experts, an experienced front-end buddy from Hangzhou told me that it may be because the mask scheme reads the path of the bitmap object, records it, and draws it out, we scaled the width and height at the beginning, so it was not very accurate. We recommend that you use apth. the setStrokeWidth method is used to refine the width settings and try again, so I tried this and it also has some effect, however, we still cannot draw the top and bottom parts of the nail image in a very round shape, which is still flat, and there will still be some ugly white lines in the middle of the image, there is no fundamental solution to the problem. Let's look at the app masking done by ios buddies. The hood effect is very good. If you look at what you have done, you can't help but feel a little lost. After trying for several days, you still haven't been able to solve the problem. How can the boss look at it from time to time, whenever I see this, I mention that this place is not perfect, and I am a little embarrassed. Well, I have to implement it as hard as possible, it may be for the dignity of an Android developer. If the idea is good, it will work hard, but where is the idea? In other words, I want to solve the current problem. After thinking twice, I decided to change the scheme of the mask painting process, so I didn't need to read or draw the path scheme, I searched for a large circle on Goole. I thought that Android has its own image mask API, but I have never tried it before. This time it may solve this headache, here is a piece of code:

// Use PorterDuff. SRC_IN or DST_IN of Mode uses the intersection of the shape layer and the display layer to obtain the private Bitmap createImage () {if (shapeLayerBitmap = null) {return null ;} if (showLayerBitmap = null) {return null;} mWidth = getMeasuredWidth (); mHeight = getMeasuredHeight (); BitmapFactory. options options = new BitmapFactory. options (); options. inJustDecodeBounds = false; // shapeLayerBitmap = getBitmapFromDrawable (shapeLayerDrawable); shapeLayerBitmap = BitmapFactory. decodeResource (context. getResources (), maskResId, options); // showLayerBitmap = getBitmapFromDrawable (getDrawable (); Paint paint = new Paint (); paint. setAntiAlias (true); paint. setDither (true); paint. setXfermode (null); if (mWidth = 0 | mHeight = 0) {return null;} Bitmap result = Bitmap. createBitmap (mWidth, mHeight, Bitmap. config.ARGB_8888); // Bitmap finalBmp = Bitmap. createBitmap (mWidth, mHeight, Bitmap. config. ARGB_8888); Canvas canvas = new Canvas (result); RectF rectf = new RectF (0, 0, mWidth, mHeight); canvas. saveLayer (rectf, null, Canvas.ALL_SAVE_FLAG); If (null! = ShowLayerBitmap & mWidth! = 0 & mHeight! = 0) {showLayerBitmap = getCenterCropBitmap (showLayerBitmap, mWidth, mHeight); canvas. drawBitmap (showLayerBitmap, 0, 0, paint);} if (null! = ShapeLayerBitmap & mWidth! = 0 & mHeight! = 0) {// trim = round (shapeLayerBitmap, mWidth, mHeight); shapeLayerBitmap = round (round, mWidth, mHeight); paint. setXfermode (new porterduxfermode (PorterDuff. Mode.DST_IN); Canvas. drawBitmap (shapeLayerBitmap, 0, 0, paint);} canvas. restore (); return result ;}

I posted a method that can be directly used. In fact, when I first started using this method, there was always a problem. After debugging several times, I could use it normally. I deeply felt that it was not easy for programmers to move bricks, it's not easy to tune bugs !!! In this way, you can perfectly mask any custom imageview control in the shape you want, and attach a few:

I thought all the problems had been solved, so I had no worries. However, the bug came again. As this custom imageView was used too frequently, each interface had several hand-shaped models, there are 6 to 7 custom imageview controls in each nail position of each hand shape. oom is coming. This headache bug should be optimized, without optimization, the user crashes directly. The boss does not scold me, So I carefully check any part of the custom control that can optimize and release the memory. Of course, this is a headache, I thought there would be no coupling impact because I should move it a little bit, and the result was a direct crash when it ran. After so many times, my neural line almost collapsed, finally, a method for compressing image resources is defined to solve this problem, because each time the code dynamically sets the masked image resources and the image resources to be masked, the image resources are not compressed, so there are so many calls, it will certainly be out of memory (oom), and this method works very well, and there will be no oom exception, and because it changes the size of the initial image resources, the loading speed is significantly improved during user operations, the experience is much smoother, and the Code for compressing images is pasted.

Public Bitmap getCompressBitmap (int resid) {BitmapFactory. options opts = new BitmapFactory. options (); // new output object opts. inJustDecodeBounds = true; // if it is set to true, only BitmapFactory of width and height is returned. decodeResource (context. getResources (), resid, opts); // set the int w, h; w = opts. outWidth; // obtain the width and height h = opts. outHeight; if (w> h) {opts. inSampleSize = w/200; // if it is a horizontal chart, set inSampleSize in proportion to width} else {opts. inSampleSize = h/200; // same as above} opts. inJustDecodeBounds = false; // remember to set false to get the graph. Otherwise, the returned value is still Bitmap bm = BitmapFactory. decodeResource (context. getResources (), resid, opts); // you can get the image. return bm ;}

Finally, add custom control attributes to attrs. xml in the values package. If the xml file does not exist in the values package, right-click and create xml.

 
         
 

It is as basic as the general imageview control. To use a static mask, you only need to add the custom attribute in the layout!

 

This way, the effect is indeed OK. Looking at a custom control, I am very excited. Haha.

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.