Android 根据屏幕尺寸适配控件大小(按比例缩放)

在写布局时就在想有没有一种方式跟随屏幕大小自动缩放呢?

寻思半天不如上手写个出来

package com.android.juzi.layout;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.widget.AbsListView;
import android.widget.TextView;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class Container {
	public static int ORIGINAL_W = 720;
	//重要:开发者设备屏幕宽度,view大小是跟随这个设置的
	private static boolean yool;//是否启动过
	private boolean icu = true;
	private int width;
	private View rootView;
	private Exclude exclude;
	private Class[] view_Optimize;
	private boolean width_Height,padding,text,margin;
	private Map<Class,Boolean> list = new HashMap<>();
	public Container(Activity a) {
		if (a == null) {
			log("Activity == null");
			return;}
		ViewGroup v = a.findViewById(android.R.id.content);
		//获取setContentView的布局
		init(a, v);
	}
	public Container(View v) {
		if (v == null) {
			log("View == null");
			return;}
		init(v.getContext(), v);
	}
	public Container(Context c, int i) {
		if (c == null) {
			log("Context == null");
			return;}
		LayoutInflater layoutInflater = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		if (layoutInflater == null) {
			throw new AssertionError("LayoutInflater构建错误.");
		}
		View v = layoutInflater.inflate(i, null, false);
		init(c, v);
	}
	private void init(Context c, View v) {
		if (c == null || v == null) {return;}
		Resources res = c.getResources();
        DisplayMetrics metrics = res.getDisplayMetrics();
        int w = metrics.widthPixels,
			h = metrics.heightPixels;
		width = w < h ? w : h;
		rootView = v;
	}
	public boolean isLoad() {
		/**
		 是否启动过
		 运行后view宽高已经被改变
		 再次运行view就会越来越小/大
		 **/
		return this.yool;
	}
	public int getDisplayWidth() {
		return width;
	}
	public Container addIsolateView(Class[] c) {
		if (c == null) {return null;}
		for (int i=0;i < c.length;i++) {
			addIsolateView(c[i]);
		}
		return this;
	}
	public Container addIsolateView(Class s) {
		return addIsolateView(s, false);
	}
	public Container addIsolateView(Class...s, boolean...b) {
		if (s == null || b == null) {return null;}
		if (s.length != b.length) {return null;}
		for (int i=0;i < s.length;i++) {
			addIsolateView(s[i], b[i]);
		}
		return this;
	}
	public Container addIsolateView(Class...s, boolean b) {
		if (s == null) {return null;}
		for (int i=0;i < s.length;i++) {
			addIsolateView(s[i], b);
		}
		return this;
	}
	public Container addIsolateView(Class s, boolean b) {
		/**
		 插入需要排除的View.class

		 参数2仅对ViewGroup生效
		 参数2代表是否修改自己
		 true自己会修改,子控件不会修改
		 false自己和子控件都不会修改
		 **/
		if (s == null) {return null;}
		list.put(s, b);
		return this;
	}
	public Container setExclude(Exclude e) {
		return setExclude(new Class[]{View.class}, e);
	}
	public Container setExclude(Class v, Exclude e) {
		return setExclude(new Class[]{v}, e);
	}
	public Container setExclude(Class...v, Exclude e) {
		/**通过view.class回调
		 若是view等于这个class那么就回调
		 可用于列表适配器刷新以及设置view的其它属性
		 **/
		view_Optimize = v;
		exclude = e;
		return this;
	}
	public int calculate(int i) {
		return calculate(((double)width) / ((double)ORIGINAL_W), i);
	} 
	public View startSkip() {
		//重新开始,会导致view大小持续增大或增小
		if (rootView == null || !icu) {return rootView;}
		if ((width_Height && padding) && (text && margin)) {
			log("无可修改项目!");
			return rootView;}
		dateView(rootView, width);
		this.yool = true;
		return rootView;
	}
	public View start() {
		//启动,不能第二次启动
		if (!this.yool) {
			startSkip();
		} else {
			log("start已运行过!");
		}
		return rootView;
	}
	public void quit() {
		//标记放弃运行
		icu = false;
	}
	public static interface Exclude {
		void onView(Container con, View v, Class c);
	}
	public Container refuse_Width_Height() {
		width_Height = true;
		//拒绝修改宽高
		return this;
	}
	public Container refuse_Padding() {
		padding = true;
		//拒绝修改内边距
		return this;
	}
	public Container refuse_TextSize() {
		text = true;
		//拒绝修改文字大小
		return this;
	}
	public Container refuse_Margin() {
		margin = true;
		//拒绝修改外边距
		return this;
	}
	private boolean[] isInstanceofView(View v) {
		/**排除列表,排除控件**/
        for (Class o:list.keySet()) {
			if (isInstanceof(v, o) || !icu) {
				return new boolean[]{false,list.get(o)};
			}
        }
		return new boolean[]{true,true};
	}
	private int calculate(double w, int old) {//计算宽度
		if (old < 1) {return old;}
		if (w > 0) {
			return (int)(old * w);
		}
		return old;
	}
	private void dateView(View view, int w) {//获取view
		if (view == null || !icu) {return;}
		if (ORIGINAL_W == w) {return;}
		boolean[] rt = isInstanceofView(view);//排除
		if (!rt[1]) {return;}
		try {
			//更新view,使用宽度计算相差,并修改
			datalayout(view, ((double)w) / ((double)ORIGINAL_W));
			view.invalidate();
			view.requestLayout();
		} catch (Exception e) {
			log("dateView: " + e.toString());
			e.printStackTrace();
		}

		if (view instanceof ViewGroup) {
			if (!rt[0]) {return;}
			View[] children = null;
			try {
				Field field = ViewGroup.class.getDeclaredField("mChildren");
				field.setAccessible(true);
				children = (View[]) field.get((ViewGroup) view);
				//通过反射获取ViewGroup内的子控件
				//历遍获取子控件
			} catch (Exception e) {
				log("dateView: " + e.toString());
			} 
			if (children == null) {return;}
			for (View child : children) {
				if (!icu) {return;}
				dateView(child, w);//重新执行自己
			}
			if (view instanceof AbsListView) {
				AbsListView abs = (AbsListView)view;
				abs.setAdapter(abs.getAdapter());
				//重设适配器,防止适配器内的数据未经过更新就直接更改view属性
			}
		}
		if (exclude != null && view_Optimize != null) {
			for (Class o:view_Optimize) {
				if (!icu) {return;}
				if (isInstanceof(view, o)) {
					exclude.onView(this, view, o);
					//回调
				}
			}
		}
	}
	private void datalayout(View v, double w) throws Exception {
		if (v == null || !icu) {return;}
		LayoutParams params = getLayoutParams(v);
		//修改内边距
		if (!padding) {
			data_Padding(v, w);
		}
		//修改TextView文字大小
		if (!text) {
			data_Text(v, w);
		}
		//修改view宽高
		if (!width_Height) {
			params = data_Width_Height(params, w);
		}
		//修改外边距
		if (!margin) {
			params = data_Margin(params, w);
		}
		v.setLayoutParams(params);
	}
	//如果view无LayoutParams则会创建一个
	private LayoutParams getLayoutParams(View v) {
		LayoutParams params = v.getLayoutParams();
		if (params == null) {
			int w_ = v.getMeasuredWidth(),
				h_ = v.getMeasuredHeight(),
				z_ = 30;
			params = new LayoutParams(w_ > 0 ? w_ : z_, h_ > 0 ? h_ : z_);
		}
		return params;
	}
	//宽高
	private LayoutParams data_Width_Height(LayoutParams params, double w) {
		params.width = calculate(w, params.width);
		params.height = calculate(w, params.height);
		return params;
	}
	//内边距大小
	private void data_Padding(View v, double w) {
		int left = calculate(w, v.getPaddingLeft());
		int top = calculate(w, v.getPaddingTop());
		int right = calculate(w, v.getPaddingRight());
		int bottom = calculate(w, v.getPaddingBottom());
		v.setPadding(left, top, right, bottom);
	}
	//TextView文字大小
	private void data_Text(View v, double w) {
		//TextView文字大小
		if (!(v instanceof TextView)) {return;}
		TextView view = (TextView)v;
		view.setTextSize(TypedValue.COMPLEX_UNIT_PX, calculate(w, (int) view.getTextSize()));
	}
	//外边距大小
	private LayoutParams data_Margin(LayoutParams params, double w) {
		if (!(params instanceof MarginLayoutParams)) {return params;}
		ViewGroup.MarginLayoutParams par = (MarginLayoutParams) params;
		par.leftMargin = calculate(w, par.leftMargin);
		par.rightMargin = calculate(w, par.rightMargin);
		par.topMargin = calculate(w, par.topMargin);
		par.bottomMargin = calculate(w, par.bottomMargin);
		return par;
	}
	//自制instanceof
	//用于排除方法
	private boolean isInstanceof(Object object, Class clazz) {
		if (object == null || clazz == null || !icu) {
			return false;
		}
		String str = clazz.getName();
		if (str == object.getClass().getName()) {
			return true;
		}
		Class<?> obj = object.getClass().getSuperclass();
		String cla = obj.getName();
		String onj = Object.class.getName();
		if (str == cla) {
			return true;
		}
		while (icu) {
			if (obj == null) {return false;}
			obj = obj.getSuperclass();
			if (obj == null) {return false;}
			cla = obj.getName();
			if (str == cla) {
				return true;
			}
			if (cla == onj) {
				return false;
			} 
		}
		return false;
	}
	private void log(String s) {
		Log.w("Container", s);
	}
}

new Container(activity).getDisplayWidth()
–首先 获取当前屏幕宽度

接下来需要修改

ORIGINAL_W = int
这个全局变量值
它代表着你的屏幕也就是开发者测试的机的屏幕宽度

当你设置好宽度的时候
con = new Container(activity)
con = new Container(view)
con = new Container(context,R.layout.id)

返回大小 = calculate(w or h)
–计算与旧的差值

setExclude(class,Exclude 回调)
setExclude(class{},Exclude 回调)
setExclude(Exclude 回调)
–修改后的回调,通过view.class回调
++若是view等于这个class那么就回调
++可用于列表适配器刷新以及设置view的其它属性
++如果通过addIsolateView排除了是不会回调此方法的
new Container.Exclude()
onView(Container,view,class)

addIsolateView(Class)
addIsolateView(Class,boolean)
addIsolateView(Class{},boolean)
addIsolateView(Class{},boolean{})
–插入需要排除的View.class
++参数2仅对ViewGroup(容器)生效
++参数2代表是否修改自己
++true自己会修改,子控件不会修改
++false自己和子控件都不会修改

boolean = isLoad()
–是否启动过
++运行后view宽高已经被改变
++再次运行view就会越来越(小/大)

refuse_Margin()
–拒绝修改外边距

refuse_TextSize()
–拒绝修改文字大小

refuse_Padding()
–拒绝修改内边距

refuse_Width_Height()
–拒绝修改宽高

那么再来讲下启动方法
上面那些参数需要先设置后再启动

view = start()
–启动,不能第二次启动
++当你准备打包app时建议使用此方法启动

view = startSkip()
–启动,可以重新启动
++注意++
++此方法建议只在测试时使用
++运行后view宽高已经被改变
++再次运行view就会越来越(小/大)
++可以通过isLoad判断
if (con.isLoad()){
//已运行
}else{
//未运行
}

quit()
–标记放弃运行

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桔.com

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值