关键(一): 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 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);
		}	
	}
}

(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



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值