屏幕适配是个经常遇到的问题,下面,我以如何将一张图片不拉伸,不裁剪的方式来完整的展示一张图片;
一、首先来看一下最初的状态:
我首先在主界面放了一张图片:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.fuyunwang.myapplication8.MainActivity">
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@mipmap/pic"
/>
</RelativeLayout>
效果如下:
可以看到,这是原图的大小,当我把图片直接塞给ImageView的时候,ImageView会自己做一个屏幕的适配,保证原图展示,所以这里会出现留白。
然而当我们设置ImageView的缩放模式为:android:scaleType="centerCrop"
的时候,图片不会出现留白但会出现明显的拉伸,导致效果变差:
地球变成了椭圆这肯定是不合理的
当然,还有保证图片不拉伸能以较好的效果展示,也就是模式为:
android:scaleType="centerCrop"
这个时候图片就会裁剪一部分然后显示,这时就丢失了一部分像素,具体的我就不贴图了,用过这个模式的大家都知道
好,那么现在我们如果想既要图片不拉伸,不留白,又不能出现裁剪的情况,保证图片完整的展示我们应该怎么做呢?
这里我以自定义属性的方式来实现上述要求
二、自定义MyImageLayout实现:
我们的思路很简单,就是实现图片的完美展示。这里用到的原理就是控件的宽高比例要与图片的宽高比例相一致,保证图片的完整展示.
首先得到原始图片的宽高比例,这里图片是1024*1024的,所以比例就是1:1(我找的这张图比较特殊,如果是一张长方形的图片效果更明显);
我们得到的长/宽的比率就是1
1.好,首先,我先在工程下创建一个类,MyImageLayout继承自FrameLayout,实现三个构造方法,
2.在values目录下创建attrs.xml文件,我这里自定义属性,因为只是实现适配,所以很简单:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MyImageLayout">
<attr name="ratio" format="float"/>
</declare-styleable>
</resources>
3.在布局文件中使用属性:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:fuyunwang="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.fuyunwang.myapplication8.MainActivity">
<com.fuyunwang.myapplication8.view.MyImageLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
fuyunwang:ratio="1.0"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/pic"
/>
</com.fuyunwang.myapplication8.view.MyImageLayout>
</RelativeLayout>
4.在代码中得到宽高:
package com.fuyunwang.myapplication8.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.LoginFilter;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.FrameLayout;
import com.fuyunwang.myapplication8.R;
/**
* Created by BeautifulSoup on 2016/12/18.
*/
public class MyImageLayout extends FrameLayout {
float ratio=-1;
public MyImageLayout(Context context) {
super(context);
}
public MyImageLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.MyImageLayout);
ratio=typedArray.getFloat(R.styleable.MyImageLayout_ratio,-1);
typedArray.recycle();
Log.i("MyImageLayout: ", String.valueOf(ratio));
}
public MyImageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* OnMeasure方法实现重绘
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i("MyImageLayout: ", String.valueOf(ratio));
int width=MeasureSpec.getSize(widthMeasureSpec);
int widthMode=MeasureSpec.getMode(widthMeasureSpec);
int height=MeasureSpec.getSize(heightMeasureSpec);
int heightMode=MeasureSpec.getMode(heightMeasureSpec);
//高度已经指定,宽度不确定,这个时候需要指定控件的绝对大小
if(widthMode==MeasureSpec.EXACTLY&&heightMode!=MeasureSpec.EXACTLY&&ratio>0){
//得到真实的宽度值
int realWidth=width-getPaddingLeft()-getPaddingRight();
int realHeight= (int) (realWidth/ratio+0.5f);
//动态计算控件的宽高
height=realHeight+getPaddingTop()+getPaddingBottom();
heightMeasureSpec=MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec,heightMeasureSpec);
}
}
此时的效果就完成了