您的位置:首页 > 其它

自定义控件的方式适配图片,以及里面的一些技巧

2016-10-05 20:06 267 查看
转载本专栏每一篇博客请注明转载出处地址,尊重原创。此博客转载链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/52718489
开题前先给出一种几乎所有人都经常见的问题,如下:

布局代码

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content""
android:orientation="vertical" >

<ImageView
android:src="@drawable/recommend_56"
android:id="@+id/iv_list_item_subject_icon"
android:layout_width="match_parent"
android:layout_height="150dp"/>

</LinearLayout>


IDE渲染效果图(无需运行程序也可以看出):



问题:图片没办法填充布局,看蓝色渲染效果就能看出。

到这里,相信很多人都遇到此类事情,我想让图片整个填充我的布局,他却偏偏无法填充,是那么的难看。那么大多人,都是这么解决问题的——

在imageView里面加一行代码:android:scaleType="fitXY"。运行效果:



正好填充完毕,而且看起来感觉还不错。

但是,这样其实是有问题的,如果我把图片的高度设置的高一些,问题就很明显了。例如,我修改为高度修改为200dp。运行效果:



可以看到,都教授和女神身子都被拉长了相信把这个放到一款APP里,用户对于二位的粉丝而言,开发者要遭骂名了。

如果非要在布局文件中做这种适配,建议用android:scaleType="centerCrop",这个属性不会对图片做拉伸,他原来是对图片中心开始,按照一定的比例裁剪,保留裁剪的部分。

因为不去做拉伸,效果肯定比上边拉伸效果好很多。运行看看效果:



看!图片没被拉伸!!但是,但是这个时候估计都教授粉丝火气比上边还大,这尼玛连人都看不到了!呵呵,你把图片高度设置小一点就好了,比如设置150dp,效果肯定很好。

android:layout_height="150dp"运行:



虽然说,女神的耳朵被剪走了,但是图片应该是上边情况最好的情景了。

那么,我们肯定会想,到底有没有好的办法,让图片既可以不被拉伸,也不所示图片的内容吗?回答是肯定的!那就是今天的主题——使用自定义控件方式,解决图片适配。

思路:自定义一个控件,控件按照图片的比例来确定自己的宽高,控件确定了宽高,让Imageview匹配这个自定义控件。这样按照比例来放置的图片就可以解决上边的问题。

按照比例来确定布局高度的自定义控件。

首先,自定义一个RatioLayout继承自FrameLayout。那么到底是多大的比例?通过自定属性的方式把这个比例值传递给我们自定义的控件里面。

然后配置针对这个控件的自定义属性文件,里面的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>

<declare-styleable name="RatioLayout">
<attr name="ratio" format="float" />
</declare-styleable>

</resources>


然后计算图片的比例。宽/高。这个图片的比例结果等于2.43

那么布局中就这么写:

<com.itydl.googlepaly.ui.view.RatioLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
itydl:ratio="2.43">

<ImageView
android:id="@+id/iv_list_item_subject_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/recommend_15" />
</com.itydl.googlepaly.ui.view.RatioLayout>


(提示:记得在根布局加入自定义的命名空间)

这个歌时候,就能在自定义控件的代码中拿到这个自定义的属性值了。接下来,具体的自定义控件时测量方法,以及一些详细的diamante解释如下:

public class RatioLayout extends FrameLayout {
private float ratio;
public RatioLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

public RatioLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// “高端”手法获取属性:
// 获取自定义控件下的属性集合。如果你的属性很多的话,返回的这个集合就对应有多大
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.RatioLayout);//表示我从attrs属性集合里面,拿到了名字叫RatioLayout的属性
// 根据属性id获取属性值, 方式:
// R.styleable.名称_属性。参数一:系统生成的id=自定义控件名_属性名;第二个参数:在属性文件中的位置是第几个
ratio = typedArray.getFloat(R.styleabut_ratio, 0);
// 使用此方式拿属性必须回收TypedArray, 以释放内存le.RatioLayo
typedArray.recycle();
}

public RatioLayout(Context context) {
super(context);
}

/**
* 当前控件测量自己的宽高时,调用此方法
*/
// 要不要绘制控件的大小?
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int widthMode = MeasureSpec.getMode(widthMeasureSpec);//获取宽度模式
int heightMode = MeasureSpec.getMode(heightMeasureSpec);//获取高度模式

//控件的宽高,并非图片的宽高
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);

// MeasureSpec.EXACTLY 确定值, 比如把宽高值写死dp,类似match_parent
// MeasureSpec.AT_MOST 至多, 能撑多大就多大, 类似wrap_content
// MeasureSpec.UNSPECIFIED 未指定大小

//按比例计算图片高度的前提是,宽度模式是确定的,即是MeasureSpec.AT_MOST,高度是不确定的。这两个条件少一个,都没有下面重新按照比例计算的必要了。
if (widthMode == MeasureSpec.EXACTLY//ratio要大于零、宽度确定、高度不确定才有必要计算高度值
&& heightMode != MeasureSpec.EXACTLY && ratio > 0) {
// 1. 根据布局宽度推算图片宽度
int imageWidth = widthSize - getPaddingLeft() - getPaddingRight();//【在布局文件中如果控件设置了padding的话图片小于控件宽度,不设置则图片宽与控件一样】
// 2. 根据图片宽度和宽高比,推算图片高度
int imageHeight = (int) (imageWidth / ratio+ 0.5f);//ratio是通过宽/高计算出来的
// 3. 根据图片高度, 推算控件(布局)最新高度
heightSize = imageHeight + getPaddingTop() + getPaddingBottom();//如果设置了padding就大于图片高度,如果没加,则相等
// 4. 重新定义高度模式。根据布局高度以及高度模式, 推算heightMeasureSpec
heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize,
MeasureSpec.EXACTLY);
}

//根据最新的高度宽度去测量
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

}


这个时候,通过渲染是看不出来,可以直接运行一下看看是否达到了惊人的效果:



可以看到,这是最好的展示效果。都教授还是那个都教授,女神也都展示了出来。

到此,通过自定义控件适配图片就完毕了。再说一下里面的“小技巧”,就是另一种“高端”方式获取属性值。过程如下:

// “高端”手法获取属性:
// 获取自定义控件下的属性集合。如果你的属性很多的话,返回的这个集合就对应有多大
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.RatioLayout);
// 根据属性id获取属性值, 方式:
// R.styleable.名称_属性。参数一:系统生成的id=自定义控件名_属性名;第二个参数:在属性文件中的位置是第几个
ratio = typedArray.getFloat(R.styleable.RatioLayout_ratio, 0);
// 使用此方式拿属性必须回收TypedArray, 以释放内存
typedArray.recycle();


当自定义控件的属性很多的时候,这种方式就比较前卫一点了。

所有知识都介绍完了,欢迎关注本博客,不定期推送文章哦~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐