Android自定义属性实现图片屏幕的适配

来源:互联网 发布:网络狼人杀发言技巧 编辑:程序博客网 时间:2024/06/02 03:21

屏幕适配是个经常遇到的问题,下面,我以如何将一张图片不拉伸,不裁剪的方式来完整的展示一张图片;
一、首先来看一下最初的状态:
我首先在主界面放了一张图片:

<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);    }}

此时的效果就完成了

1 0