关键(一): android不同机型的适配的解决方案之按比例伸缩篇
android机型适配,这是android开发者心中的一个痛,真的很痛。
android不同机型的适配的解决方案(完整篇)
上面这篇文章,是我把谷歌官方的适配解决方案的翻译。但是官方的机型适配解决方案还是有几个缺点:
(1)机型适配的分辨率太多,并且每个分辨率都要分别调整UI布局
**-hdpi, **-mdpi, **-lmdpi, **-xdpi, **-xxdpi, *******等等,这些分辨率只能是大概的针对各个机型,但是对于特定的机型,UI效果是非常的不理想,要调整许多参数,就是在同一个分辨率下,不同的机型,也是要修改许多的参数,这样来说,机型适配的工作量,是非常大的,这也是开发者心中痛的一个重要原因。
(2)机型适配主方式,不能做到个各个机型的UI效果一致
针对不同分辨率的机型,分别做UI调整,是能适配各种机型,但是不能做到各个机型UI效果一致,这其实是机型适配的一个非常大的缺点,也就是说,其实他还是没有提供一个统一的适配所有机型的解决方案
比例伸缩适配(PercentageLayout)
有没有一种界面的适配方案,能解决上面二个缺点呢,我这提供一个解决方案,比例伸缩适配(PercentageLayout),能很好的把所有机型当做一个分辨率来对待,并能保持所有机型UI效果的一致。(说明,这不是我想出来的,是别人做出来的)。
比例伸缩适配(PercentageLayout)核心思想:
PercentageLayout 继承相对布局RelativeLayout,然后绘制UI时,对PercentageLayout 自己和PercentageLayout 下的所有控制margin参数,宽,高,padding参数,还有TextView的字体大小按比例来进行伸缩(放大或缩小)。
比例伸缩适配(PercentageLayout)的核心代码:
private void scaleChild(View child){float widthScale = screenWidth/baseWidth;float heightScale = screenHeight/baseHeight;Log.i(TAG,"scaleChild---widthScale="+widthScale+"--heightScale="+heightScale);Log.i(TAG,"!Boolean.TRUE.equals(scaledMap.get(child)):"+(!Boolean.TRUE.equals(scaledMap.get(child))));if(!Boolean.TRUE.equals(scaledMap.get(child))){ ViewGroup.LayoutParams st = child.getLayoutParams(); if(st instanceof ViewGroup.MarginLayoutParams){ MarginLayoutParams margin = (MarginLayoutParams)st; margin.leftMargin*=widthScale; margin.rightMargin*=widthScale; margin.topMargin*=heightScale; margin.bottomMargin*=heightScale; Log.i(TAG,"scaleChild---margin.leftMargin="+margin.leftMargin+"--margin.rightMargin="+margin.rightMargin +"--margin.topMargin="+margin.topMargin+"--margin.bottomMargin="+margin.bottomMargin); } boolean constraitRatio = false; if(st instanceof PercentageLayout.LayoutParams){ constraitRatio = ((PercentageLayout.LayoutParams)st).constraitRatio; } Log.i(TAG,"scaleChild--origin---st.width="+st.width+"--st.height="+st.height); if(st.width>0){ if(child!=this||scaleItSelf){ if(!constraitRatio){ st.width=(int) (st.width*widthScale); Log.i(TAG,"scaleChild---st.width="+st.width); }else{ st.width=(int) (st.width*heightScale); Log.i(TAG,"scaleChild--else---st.width="+st.width); } } } if(st.height>0){ if(child!=this||scaleItSelf){ st.height*=heightScale; Log.i(TAG,"scaleChild---st.height="+st.height); } } Drawable background = child.getBackground(); if(background == null||!(background instanceof NinePatchDrawable)){ Log.i(TAG,"scaleChild---child.getPadding--"+(int)(child.getPaddingLeft())+","+(int)(child.getPaddingTop())+"," +(int)(child.getPaddingRight())+","+(int)(child.getPaddingBottom())); child.setPadding((int)(child.getPaddingLeft()*widthScale), (int)(child.getPaddingTop()*heightScale), (int)(child.getPaddingRight()*widthScale), (int)(child.getPaddingBottom()*heightScale)); Log.i(TAG,"scaleChild---child.setPadding--"+(int)(child.getPaddingLeft()*widthScale)+","+(int)(child.getPaddingTop()*heightScale)+"," +(int)(child.getPaddingRight()*widthScale)+","+(int)(child.getPaddingBottom()*heightScale)); } if(strenchTextsize && heightScale!=1 && child instanceof TextView){ if(screenHeight <= 320){ heightScale = widthScale; } TextView t = (TextView)child; float size = t.getTextSize(); t.setTextSize(TypedValue.COMPLEX_UNIT_PX, size*heightScale); Log.i(TAG,"scaleChild---t.setTextSize--size="+size+"size*heightScale="+size*heightScale); if(t instanceof AutoCompleteTextView){ AutoCompleteTextView at = (AutoCompleteTextView)t;// at.setDropDownHeight((int) (at.getDropDownHeight()*heightScale)); } } scaledMap.put(child, Boolean.TRUE); } if((child instanceof ViewGroup) && !(child instanceof PercentageLayout)){ Log.i(TAG,"(child instanceof ViewGroup) && !(child instanceof PercentageLayout):"+ ((child instanceof ViewGroup) && !(child instanceof PercentageLayout))); scaleDimensions((ViewGroup) child); }}
比例伸缩适配(PercentageLayout)的一个Demo:
(1)PercentageLayout.java
package com.example.testpercentagelayout;import java.util.HashMap;import java.util.Map;import android.content.Context;import android.content.res.TypedArray;import android.graphics.drawable.Drawable;import android.graphics.drawable.NinePatchDrawable;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.util.Log;import android.util.TypedValue;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.AutoCompleteTextView;import android.widget.ImageView;import android.widget.PopupWindow;import android.widget.RelativeLayout;import android.widget.TextView;public class PercentageLayout extends RelativeLayout {private static String TAG = "PercentageLayout_test";private float baseWidth = 854;private float baseHeight = 480;private float screenWidth = 427;private float screenHeight = 240;private boolean strenchTextsize = true;/**是否对自身大小进行缩放*/private boolean scaleItSelf = true;private Map<View,Boolean>scaledMap = new HashMap<View,Boolean>();public PercentageLayout(Context context) {super(context);// TODO Auto-generated constructor stub}public PercentageLayout(Context context, AttributeSet attrs) {this(context, attrs,0);// TODO Auto-generated constructor stub}public PercentageLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initializeScreenSize(context);// TODO Auto-generated constructor stubTypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PercentageLayout);baseWidth = a.getDimension(R.styleable.PercentageLayout_base_width, baseWidth);baseHeight = a.getDimension(R.styleable.PercentageLayout_base_height, baseHeight);screenWidth = a.getDimension(R.styleable.PercentageLayout_des_width, screenWidth);screenHeight = a.getDimension(R.styleable.PercentageLayout_des_height, screenHeight);strenchTextsize = a.getBoolean(R.styleable.PercentageLayout_strenchTextsize, strenchTextsize);scaleItSelf = a.getBoolean(R.styleable.PercentageLayout_scaleItSelf, scaleItSelf);a.recycle();Log.i(TAG,"PercentageLayout--baseWidth:"+baseWidth+"--baseHeight:"+baseHeight+"--screenWidth:"+screenWidth+"--screenHeight:"+screenHeight+"--strenchTextsize:"+strenchTextsize+"--scaleItSelf:"+scaleItSelf);}public void initializeScreenSize(Context context) {DisplayMetrics metrics = context.getResources().getDisplayMetrics();screenHeight = Math.min(metrics.heightPixels,metrics.widthPixels);screenWidth = Math.max(metrics.widthPixels,metrics.heightPixels);Log.i(TAG, "initializeScreenSize---屏幕宽度:" + metrics.widthPixels + "px 屏幕高度:"+ metrics.heightPixels + "px");Log.i(TAG, "initializeScreenSize---屏幕密度:" + metrics.density);Log.i(TAG, "initializeScreenSize---屏幕DPI:" + metrics.densityDpi);Log.i(TAG,"initializeScreenSize----screenWidth="+screenWidth+" --screenHeight="+screenHeight);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {scaleDimensions(this);super.onMeasure(widthMeasureSpec, heightMeasureSpec);}private void scaleDimensions(ViewGroup group){int count = group.getChildCount();Log.i(TAG,"scaleDimensions-----count="+count);if(group instanceof PercentageLayout){Log.i(TAG,"scaleDimensions-----scaleChild(group)");scaleChild(group); } for (int i = 0; i < count; i++) { View child = group.getChildAt(i); Log.i(TAG,"scaleDimensions-----scaleChild(child)"); scaleChild(child); }}private void scaleChild(View child){float widthScale = screenWidth/baseWidth;float heightScale = screenHeight/baseHeight;Log.i(TAG,"scaleChild---widthScale="+widthScale+"--heightScale="+heightScale);Log.i(TAG,"!Boolean.TRUE.equals(scaledMap.get(child)):"+(!Boolean.TRUE.equals(scaledMap.get(child))));if(!Boolean.TRUE.equals(scaledMap.get(child))){ ViewGroup.LayoutParams st = child.getLayoutParams(); if(st instanceof ViewGroup.MarginLayoutParams){ MarginLayoutParams margin = (MarginLayoutParams)st; margin.leftMargin*=widthScale; margin.rightMargin*=widthScale; margin.topMargin*=heightScale; margin.bottomMargin*=heightScale; Log.i(TAG,"scaleChild---margin.leftMargin="+margin.leftMargin+"--margin.rightMargin="+margin.rightMargin +"--margin.topMargin="+margin.topMargin+"--margin.bottomMargin="+margin.bottomMargin); } boolean constraitRatio = false; if(st instanceof PercentageLayout.LayoutParams){ constraitRatio = ((PercentageLayout.LayoutParams)st).constraitRatio; } Log.i(TAG,"scaleChild--origin---st.width="+st.width+"--st.height="+st.height); if(st.width>0){ if(child!=this||scaleItSelf){ if(!constraitRatio){ st.width=(int) (st.width*widthScale); Log.i(TAG,"scaleChild---st.width="+st.width); }else{ st.width=(int) (st.width*heightScale); Log.i(TAG,"scaleChild--else---st.width="+st.width); } } } if(st.height>0){ if(child!=this||scaleItSelf){ st.height*=heightScale; Log.i(TAG,"scaleChild---st.height="+st.height); } } Drawable background = child.getBackground(); if(background == null||!(background instanceof NinePatchDrawable)){ Log.i(TAG,"scaleChild---child.getPadding--"+(int)(child.getPaddingLeft())+","+(int)(child.getPaddingTop())+"," +(int)(child.getPaddingRight())+","+(int)(child.getPaddingBottom())); child.setPadding((int)(child.getPaddingLeft()*widthScale), (int)(child.getPaddingTop()*heightScale), (int)(child.getPaddingRight()*widthScale), (int)(child.getPaddingBottom()*heightScale)); Log.i(TAG,"scaleChild---child.setPadding--"+(int)(child.getPaddingLeft()*widthScale)+","+(int)(child.getPaddingTop()*heightScale)+"," +(int)(child.getPaddingRight()*widthScale)+","+(int)(child.getPaddingBottom()*heightScale)); } if(strenchTextsize && heightScale!=1 && child instanceof TextView){ if(screenHeight <= 320){ heightScale = widthScale; } TextView t = (TextView)child; float size = t.getTextSize(); t.setTextSize(TypedValue.COMPLEX_UNIT_PX, size*heightScale); Log.i(TAG,"scaleChild---t.setTextSize--size="+size+"size*heightScale="+size*heightScale); if(t instanceof AutoCompleteTextView){ AutoCompleteTextView at = (AutoCompleteTextView)t;// at.setDropDownHeight((int) (at.getDropDownHeight()*heightScale)); } } scaledMap.put(child, Boolean.TRUE); } if((child instanceof ViewGroup) && !(child instanceof PercentageLayout)){ Log.i(TAG,"(child instanceof ViewGroup) && !(child instanceof PercentageLayout):"+ ((child instanceof ViewGroup) && !(child instanceof PercentageLayout))); scaleDimensions((ViewGroup) child); }}@Overrideprotected boolean checkLayoutParams(ViewGroup.LayoutParams p) {return p instanceof PercentageLayout.LayoutParams;}@Overrideprotected ViewGroup.LayoutParams generateDefaultLayoutParams() {return super.generateDefaultLayoutParams();}@Overridepublic RelativeLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {return new LayoutParams(getContext(),attrs);}@Overrideprotected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {return new LayoutParams(p);}public float getBaseWidth() {return baseWidth;}public void setBaseWidth(float baseWidth) {this.baseWidth = baseWidth;}public float getBaseHeight() {return baseHeight;}public void setBaseHeight(float baseHeight) {this.baseHeight = baseHeight;}public float getScreenWidth() {return screenWidth;}public void setScreenWidth(float screenWidth) {this.screenWidth = screenWidth;}public float getScreenHeight() {return screenHeight;}public void setScreenHeight(float screenHeight) {this.screenHeight = screenHeight;}public static class LayoutParams extends RelativeLayout.LayoutParams{/**是否固定长宽比,默认为true*/private boolean constraitRatio = true;/**是否根据屏幕重置图片大小,仅用于ImageView并且layout_width=wrap_content的情况,默认为true*/private boolean strenchImage = true;/**是否根据屏幕大小重置文字大小,仅用于TextView,默认为true*/private boolean strenchTextsize = true;/**是否在固定长宽比时使用屏幕高度作为计算基准,默认为true*/private boolean resizeByHeight = true;public LayoutParams(Context c, AttributeSet attrs) {super(c, attrs);// TODO PercentageLayout.LayoutParams(Context c, AttributeSet attrs)TypedArray a = c.obtainStyledAttributes(attrs,R.styleable.PercentageLayout);constraitRatio = a.getBoolean(R.styleable.PercentageLayout_constraitRatio, constraitRatio);strenchImage = a.getBoolean(R.styleable.PercentageLayout_strenchImage, strenchImage);strenchTextsize = a.getBoolean(R.styleable.PercentageLayout_strenchTextsize, strenchTextsize);resizeByHeight = a.getBoolean(R.styleable.PercentageLayout_resizeByHeight, resizeByHeight);a.recycle();Log.i(TAG,"LayoutParams--constraitRatio:"+constraitRatio+"--strenchImage:"+strenchImage+"--strenchTextsize:"+strenchTextsize+"--resizeByHeight:"+resizeByHeight);}public LayoutParams(int arg0, int arg1) {super(arg0, arg1);}public LayoutParams(ViewGroup.LayoutParams arg0) {super(arg0);}public LayoutParams(MarginLayoutParams arg0) {super(arg0);}}}
(2)res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="PercentageLayout"> <attr name="base_width" format="dimension" /> <attr name="base_height" format="dimension" /> <attr name="des_width" format="dimension" /> <attr name="des_height" format="dimension" /> <attr name="strenchTextsize" format="boolean" /> <attr name="scaleItSelf" format="boolean" /> <attr name="constraitRatio" format="boolean" /> <attr name="resizeByHeight" format="boolean" /> <attr name="strenchImage" format="boolean" /> </declare-styleable></resources>
(3)res/layout/activity_test_percentage_layout_main.xml
<com.example.testpercentagelayout.PercentageLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/PL" android:layout_width="500px" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:background="@drawable/bj" tools:context=".TestPercentageLayoutMainActivity" ><ImageView android:id="@+id/my_iv_pl" android:layout_width="wrap_content" android:layout_height="wrap_content"android:layout_marginLeft="100px" android:layout_marginRight="100px" android:layout_marginTop="200px" android:layout_marginBottom="200px" android:background="@drawable/btn_bg_yellow" /> <TextView android:id="@+id/my_tv_pl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="50px" android:layout_below="@id/my_iv_pl" android:text="@string/hello_world" android:textSize="35px"/> </com.example.testpercentagelayout.PercentageLayout>
下载地址:
http://download.csdn.net/detail/hfreeman2008/7509507
参考文献:
1.android不同机型的适配的解决方案(完整篇)
http://blog.csdn.net/hfreeman2008/article/details/23749007
更多相关文章
- 关于android:layout_weight属性使用注意事项
- 关于android:layout_weight属性使用注意事项
- 关于android:layout_weight属性使用注意事项
- 2011.10.14(2)——— android 仿照微信的图片展示功能 之 放大超过
- 2011.10.14(2)——— android 仿照微信的图片展示功能 之 放大超过
- 快速进入Android世界
- android:layout_weight总有你不知道的用法.
- Android屏幕密度(Density)和分辨率的关系
- Android屏幕适配攻略