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(安卓)6.0 变更
  2. android在程序中打开另一个程序
  3. Android(安卓)SDK Manager Failed to fet
  4. 初涉Android设计原则,设计模式
  5. 【Android】OpenGL ES---绘制3D图形、应
  6. 快速学会开发Android(安卓)App
  7. android中的4种launchmode详解
  8. Flutter Android(安卓)Toast Message(flu
  9. Android(安卓)Manifest.xml解析
  10. Android(安卓)FrameWork——ActivityMana