android机型适配,这是android开发者心中的一个痛,真的很痛。
android不同机型的适配的解决方案(完整篇)
**-hdpi, **-mdpi, **-lmdpi, **-xdpi, **-xxdpi, *******等等,这些分辨率只能是大概的针对各个机型,但是对于特定的机型,UI效果是非常的不理想,要调整许多参数,就是在同一个分辨率下,不同的机型,也是要修改许多的参数,这样来说,机型适配的工作量,是非常大的,这也是开发者心中痛的一个重要原因。
针对不同分辨率的机型,分别做UI调整,是能适配各种机型,但是不能做到各个机型UI效果一致,这其实是机型适配的一个非常大的缺点,也就是说,其实他还是没有提供一个统一的适配所有机型的解决方案
有没有一种界面的适配方案,能解决上面二个缺点呢,我这提供一个解决方案,比例伸缩适配(PercentageLayout),能很好的把所有机型当做一个分辨率来对待,并能保持所有机型UI效果的一致。(说明,这不是我想出来的,是别人做出来的)。
PercentageLayout 继承相对布局RelativeLayout,然后绘制UI时,对PercentageLayout 自己和PercentageLayout 下的所有控制margin参数,宽,高,padding参数,还有TextView的字体大小按比例来进行伸缩(放大或缩小)。
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); } }
(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 stub TypedArray 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); } @Override protected 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); } } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof PercentageLayout.LayoutParams; } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return super.generateDefaultLayoutParams(); } @Override public RelativeLayout.LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(),attrs); } @Override protected 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); } } }
<?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>
<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