Android Custom Control series eight: Detailed Onmeasure () (ii)--using onmeasure measurement to achieve picture stretching never deformation, solve screen adaptation problems

Source: Internet
Author: User

The previous article explained in detail how the Onmeasure/measure method works in Android custom controls, see blog: Android Custom Control Series seven: detailed in the Onmeasure () method, how to measure a control size (a), To really practice today, let these two methods show great divinity to help us deal with the picture screen adaptation problems.


Please respect the original labor results, reproduced please specify the source: http://blog.csdn.net/cyp331203/article/details/45038329, not allowed to use for commercial or profit purposes, offenders must investigate.


issues that you may encounter with ImageView


In the Android application, there is no picture of the display, ImageView, Carousel, Viewpager, and so on, many are to display pictures, such as a banner of the effect of the carousel, see Blog: The effect of the ads bar----viewpager load large picture ( LruCache) and timed refresh, many times, we want the image to be able to fill the width of the parent form, so it is more in line with the aesthetic view of people, but the question is followed, that is, how highly defined?? Let's look at the definition of an ordinary imageview XML layout file:

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"    xmlns:tools= "http// Schemas.android.com/tools "    android:layout_width=" match_parent "    android:layout_height=" Match_parent "    android:orientation= "vertical" >    <imageview        android:layout_width= "Fill_parent"        android: layout_height= "Wrap_content"        android:src= "@drawable/recommend_39"/>    <textview        android:layout _width= "Wrap_content"        android:layout_height= "wrap_content"        android:text= "descriptive text information ... "/></linearlayout>..... ..."...... "

To make it easier to see, I added a textview of the information described below in ImageView, when the parent control is populated with the parent form, while ImageView is: Horizontally fills the parent form, wraps the contents vertically, and the text is the contents of the package; then look at the display:



The blue box above is the range of ImageView, this effect is generally not what we want, then if you want to imageview in the picture can fill the imageview of the entire form? Add an attribute: ScaleType, as follows:

    <imageview        android:layout_width= "fill_parent"        android:layout_height= "Wrap_content"        android: Scaletype= "Fitxy"        android:src= "@drawable/recommend_39"/>

Effect


As you can see, the fill is filled, but it also distorts the picture because of the longitudinal stretching. How do you do that?


We look closely, it is not difficult to find ImageView vertical height is the package content: wrapcontent, some students may think, can be directly here to imageview a specific dip value, let this imageview meet the picture aspect ratio? This is certainly possible, but it is not universal ... The following example is used to explain:


Let's start by implementing the ImageView height to get the picture to show the proportional normal in this particular simulator:


The actual pixel size of the above image is: 828*314, the ratio of width to height is about 2.43, and the simulator we use here is 480*800 (px, or pixel), that is, the width of the pixel is 480, So we're going to set the height of this imageview to how many dips can make it fit exactly 2.43 of the scale.


the relationship between PX (pixel), dpi (pixel density), dip (density independent pixels) on Android devices:


There is another piece of knowledge, dip and DPI associated with it:


Resolution (Resolution): Represents the total number of pixel points on the device screen, such as the emulator above, the screen pixel size is 480 (px) *800 (px)


DPI (pixel density): refers to pixels per inch, so the same resolution of the two devices, their DPI is likely to be different, if a phone resolution of 5 inches is 1080*1920, and a flat 9.7-inch resolution is 1080*1920, then the phone's DPI will be much higher than the tablet.


Dp/dip: Full name is Density-independent Pixel, Chinese name is "density independent pixels", that is, we often write in the XML file length unit DP. Why is it called density-independent pixels, which is actually to solve the different resolution device display effect of a unified solution, imagine, if a two mobile phone screen is the same size, such as 5 inch, a phone resolution is 720*1280, and B phone resolution is 1080* 1920; So if we want to show a picture at the top resolution: 200*200, you will find that the picture shown on a mobile phone is much smaller than the picture shown on the B phone; intuitively, the width of a cell phone is 720, and the image of 200*200 shows that almost 1/ The width of the 3, and the second view of the B phone, the width is 1080, the display 200*200 picture, then only need to occupy 1/5 less than the width, and two mobile phone size is 5 inches, so it will show the same resolution of the picture, the size of the difference. This difference is obviously not what we want.


So dip/dp, density-independent pixels came into being; it is stated that the dip is equal to the PX (pixel) value of a device with a dpi (pixel density) of 160dpi, and for other pixel density devices, the corresponding dip value is calculated based on the conversion formula, which is based on the DPI ( Proportional) to convert px (pixels) and dip (density-independent pixels):


PX = Dip * (dpi/160) dip = px/(dpi/160)

After the above conversion, since the dip and PX conversion is proportional, and this ratio is dpi/160, and DPI is based on the resolution and size of each device to get the ratio, so use the same dip to set the size of the control, on the same size of the device, Regardless of the resolution of the device, the size of the display will be the same.


method for calculating the appropriate height of ImageView


With the above knowledge, we can change the size of our ImageView:


First, the picture aspect ratio is 2.43, and the simulator screen width is 480px, so the calculation of the image should show the height is: 480/2.43=197.53px (pixels), but in general, we in the XML file, set the height of the units are dip, So here we need to use the above conversion formula: Dip = px/(dpi/160), and in the parameters of this simulator can be queried, its DPI is 240, so calculate the height should be:

197.53/(240/160) =131.68 (DIP), approximately equal to 132DP, so we set the height of the above ImageView to 132DP:

    <imageview        android:layout_width= "fill_parent"        android:layout_height= "132DP"        android:scaletype= " Fitxy "        android:src=" @drawable/recommend_39 "/>

Let's take a look at the display effect:



This shows that the scale is perfectly normal.


But does that solve the problem? The answer is no, we might as well change a simulator to show, this time choose NEXUS7 Simulator, the resolution is 1200*1920,dpi for 320,imageview parameters unchanged, then to see the effect:




Will find the picture is stretched, this is why, we can simply calculate again:

Nexus7 width is 1200px, and DPI is 320, picture scale is 2.43, then should set ImageView height DP value is: 1200/2.43/(320/160) =246.91DP, and our current height is still the previous 132DP, Of course you will find it stretched out.


What to do, a bit of a person crazy!!!


rewrite the Onmeasure method, re-measure the height of the control, achieve a variety of screen adaptive picture display



In fact, the idea is to let the control (ImageView) their own according to different equipment to help us to calculate the height, and do not need our own to calculate, how to do it? You have to use the Onmeasure method mentioned in the last blog post, the Measure/onmeasure method is unfamiliar to the students, you can go to see the Android custom Control series Seven: Detailed Onmeasure () method How to measure a control size (a) and Android Custom Control series two: Custom switch button (i) and several other articles, the following is the beginning:


The first thing to be clear is that the custom view before calling View.measure (), is not the width and height of the control, the following steps to write:


The idea is to first write a smartimageview to inherit from ImageView, and add the appropriate constructs:


Package Com.example.imageviewdemo;import Android.content.context;import Android.util.attributeset;import android.widget.imageview;/** * @author: Bitter coffee *  * @version: 1.0 *  * @date: April 14, 2015 *  * @blog: Http://blog. csdn.net/cyp331203 *  * @desc: Smartimageview, can automatically adjust the width and height according to the given picture proportion, solve the screen adaptation problem of stretching deformation */public class Smartimageview Extends ImageView {public Smartimageview (context context, AttributeSet attrs,int defstyleattr, int defstyleres) {super ( Context, Attrs, defstyleattr, defstyleres);} Public Smartimageview (context context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle);} Public Smartimageview (context context, AttributeSet Attrs) {Super (context, attrs);} Public Smartimageview (Context context) {super (context);}}


Then in Smartimageview, add a float-type member variable ratio as the scale value of the picture, and expose it to a setter method to set the picture scale.

/** picture width and height ratio */private float ratio = 2.43f;public void setratio (float ratio) {this.ratio = ratio;}


Then we'll rewrite the Onmeausre method, as follows:

@Overrideprotected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//The parent container passes over the width direction of the pattern int widthmode = Measurespec.getmode (WIDTHMEASURESPEC);//the mode int heightmode = Measurespec.getmode (Heightmeasurespec) that the parent container passes over in the height direction;// The value of the width of the parent container passed in int width = measurespec.getsize (widthmeasurespec)-Getpaddingleft ()-getpaddingright ();//The value of the height of the parent container passed INT Height = measurespec.getsize (heightmeasurespec)-Getpaddingleft ()-getpaddingright (); if (Widthmode = = measurespec.exactly&& Heightmode! = measurespec.exactly && ratio! = 0.0f) {//Judging condition is, Width mode is exactly, That is, fill the parent form or specify the width,//And the height mode is not exaclty, which means that the set is neither fill_parent nor concrete value, so it needs to be measured//and the aspect ratio of the picture has been assigned, no longer is the 0.0f//for width determination, To measure altitude height = (int) (width/ratio + 0.5f); Heightmeasurespec = Measurespec.makemeasurespec (height,measurespec.exactly);} else if (widthmode! = measurespec.exactly&& Heightmode = = measurespec.exactly && ratio! = 0.0f) {//Judging condition keep up The opposite of the face, the condition interchange of the width direction and the height direction//Indicates the height determination, to measure width = (int) (height * ratio + 0.5f); Widthmeasurespec = MEasurespec.makemeasurespec (width,measurespec.exactly);} Super.onmeasure (Widthmeasurespec, heightmeasurespec);}


For the Onmeasure method, there are a few things to note:

1, the parent container passed over the two parameters Widthmeasurespec and Heightmeasurespec, through the Measurespec.getmode () to get the pattern in the parameters, and the way the control is filled with a corresponding relationship, This is in the previous post: Android Custom Control Series Seven: detailed how to measure a control dimension in the Onmeasure () method (a) also mentioned in

①xml a fill_parent or specific value in a layout file, or a specific value that directly sets the width and height in the control's Layoutparams or layoutparams.fill_parent fills the parent container, will correspond to let the above through GetMode get parameters in the pattern is: measurespect.exactly, representing the exact value, because in addition to directly specify the value, the filling of the parent container, is also the exact value

Setting wrap_content in the ②xml layout file, or setting layoutparams.wrap_content in code, will make GetMode into Measurespect.at_most


2, for the parent container passed the height or width of the value, is not necessarily the width or height of the control to the value, this is because the pattern is different, this value represents a different meaning, it will need to measure to change the height or width of the value to achieve the desired effect.

Where, if the pattern is exactly, then the passed value is the specific meaning, it can be said that the parent container wants our control to become this specific size.

However, if the mode is At_most, then the passed value will not be a specific value, generally will be a maximum value, because at_most represents, not more than how much, then this value is not more than the upper limit.


3, we can see by getting the parent container passed the height, width of the mode and value, and then after two if-else judgment to re-measure the size of the value, the basis of two judgments is:

① when width is determined (width is exactly), height mode is not exactly (also when height is indeterminate), the height is measured in proportion to ratio

② when height is determined (height is exactly), height mode is not exactly (also when height is indeterminate), width is re-measured according to ratio ratio


4, after the measurement has been completed, because the desired width or height of the specific precise value, we again through the Measurespec.makemeasurespec () method to call the precise value and precise mode, to synthesize a width/height direction of the composite value, Finally, the synthesized values are passed to Super.onmeasure (Widthmeasurespec, Heightmeasurespec); Set the control to the size we want.


Then we can change the previous imageview in the XML layout file to: Com.example.imageviewdemo.SmartImageView


Then in the code to get its object through Findviewbyid, and then through the setratio to set the proportions of the picture, as follows:

<linearlayout xmlns:android= "http://schemas.android.com/apk/res/android"    xmlns:tools= "http// Schemas.android.com/tools "    android:layout_width=" match_parent "    android:layout_height=" Match_parent "    android:orientation= "vertical" >    <com.example.imageviewdemo.smartimageview        android:layout_ Width= "Fill_parent"        android:layout_height= "wrap_content" android:scaletype= "Fitxy" android:id= "        @+ Id/siv "        android:src=" @drawable/recommend_39 "/>    <textview        android:layout_width=" Wrap_ The content "        android:layout_height=" wrap_content "        android:text=" describes the text information ... "The/> of the" ... "...". " </LinearLayout>

Package Com.example.imageviewdemo;import Android.app.activity;import Android.os.bundle;public class MainActivity Extends Activity {@Overrideprotected void onCreate (Bundle savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.layout.activity_main);//Get Smartimageview object Smartimageview Siv = (smartimageview) findViewById ( R.ID.SIV);//Set ratio value siv.setratio (2.43f);}}


After the above, we will find that no matter what screen, whether in the horizontal screen or vertical screen, can be displayed in the correct proportion of the picture,






240*320/2.7 inch equipment NEXUS7 1200*1920 Equipment






ANDROIDTV (1920*1080) Horizontal screen display device



Finally left a small place, is to show the image of the ratio, this can have a variety of ways, one is from the server, the server is specified, then we can directly get, and then set up, and then you can measure the width of the bitmap to determine the proportion, is also possible.


The way you set up ratio can be like calling the Setratio () method above, or you can use a custom attribute to determine directly in an XML file about a custom attribute, because it is not a textual focus, Do not know the students can go to see the column of this article: Android Custom Control series four: Custom switch button (c)---Custom properties, you will understand.


Then there is another way to customize the view: The study of OnLayout method, please look forward to, thank you!


Please respect the original labor results, reproduced please specify the source: http://blog.csdn.net/cyp331203/article/details/45038329, not allowed to use for commercial or profit purposes, offenders must investigate.






Android Custom Control series eight: Detailed Onmeasure () (ii)--using onmeasure measurement to achieve picture stretching never deformation, solve screen adaptation problems

Related Article

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.