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



更多相关文章

  1. 2011.10.14(2)——— android 仿照微信的图片展示功能 之 放大超过
  2. Android屏幕适配攻略
  3. Android的Activity屏幕切换动画-左右滑动切换
  4. android屏幕分辨率详解 ldpi mdpi hdpi 程序UI自适应 《官方翻译
  5. 目前Android最全面、最易懂的Android屏幕适配解决方案
  6. Android 桌面角标在各大品牌机型上的实现
  7. Android开发屏幕适配
  8. android下的定时器在关闭屏幕后会自己停掉解决方法

随机推荐

  1. android蓝牙模块
  2. java.lang.NullPointerException Attempt
  3. CheckBox android:paddingLeft 不兼容问
  4. NestedScrollView+RecyclerView滑动冲突
  5. Android(安卓)中Timer使用(勘误)
  6. JNI 无法确定Bitmap的签名
  7. Android/Linux大于1024Bytes打印
  8. Android(安卓)SQLite使用
  9. Gradle Sync Failed,报错"could not find
  10. android 全屏实现