android界面适配难是历史原因,我们只能想办法解决。github上面已有一些布局自适应的解决方案,今天我分享的是自定义控件:RelativieLayout自适应百分比宽高。直接上菜。
一,实现的效果图
眼见为实,截图所示,宽高都是50%,实现了自适应
二,实现的原理
其实很简单,就是自定义两个属性:宽和高的百分比,让自定义的view继承 RelativeLayout。取出这两个属性的值,测量父布局的宽高,乘百分比就是实际的宽高,然后确定在父控件中的位置。
三,自定义样式属性
在values文件夹中新建attrs.xml,内容如下:
layout_widthPercent和layout_heightPercent都是浮点型,0-1之间的值,代表百分百。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="percentRelativeLayout">
<attr name="layout_widthPercent" format="float"></attr>
<attr name="layout_heightPercent" format="float"></attr>
</declare-styleable>
</resources>
四,自定义percentRelativeLayout
简单粗暴,根据xml布局中的子view的LayoutParams获取实际宽高。
public class PercentRelativeLayout extends RelativeLayout{
public PercentRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}
public PercentRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
public PercentRelativeLayout(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
// TODO Auto-generated method stub
return new LayoutParams(getContext(), attrs);
}
//测量自己
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取自身的宽高
int widthHint = View.MeasureSpec.getSize(widthMeasureSpec);
int heightHint = View.MeasureSpec.getSize(heightMeasureSpec);
for(int i = 0;i<this.getChildCount();i++){
View child = this.getChildAt(i);
//获取孩子view的布局属性
ViewGroup.LayoutParams params = child.getLayoutParams();
float widthPercent = 0;
float heightPercent = 0;
//含有自定义的属性,则获取百分百
if(params instanceof PercentRelativeLayout.LayoutParams){
widthPercent = ((PercentRelativeLayout.LayoutParams) params).getWidthPercent();
heightPercent = ((PercentRelativeLayout.LayoutParams) params).getHeightPercent();
}
if(widthPercent == 0|| heightPercent == 0){
continue;//百分百为0,跳出此次循环
}
//真实的宽高
params.width = (int) (widthPercent*widthHint);
params.height = (int) (heightPercent*heightHint);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);
}
public static class LayoutParams extends RelativeLayout.LayoutParams{
private float widthPercent;
private float heightPercent;
public float getWidthPercent() {
return widthPercent;
}
public void setWidthPercent(float widthPercent) {
this.widthPercent = widthPercent;
}
public float getHeightPercent() {
return heightPercent;
}
public void setHeightPercent(float heightPercent) {
this.heightPercent = heightPercent;
}
//构造函数里面获取自定义样式属性的值
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray array = c.obtainStyledAttributes(attrs, R.styleable.percentRelativeLayout);
widthPercent = array.getFloat(R.styleable.percentRelativeLayout_layout_widthPercent, widthPercent);
heightPercent = array.getFloat(R.styleable.percentRelativeLayout_layout_heightPercent,heightPercent);
array.recycle();
}
public LayoutParams(int w, int h) {
super(w, h);
// TODO Auto-generated constructor stub
}
public LayoutParams(android.view.ViewGroup.LayoutParams source) {
super(source);
// TODO Auto-generated constructor stub
}
public LayoutParams(MarginLayoutParams source) {
super(source);
// TODO Auto-generated constructor stub
}
}
}
五,布局中引用自定义View和属性
上菜了。不用 系统控件,用咱们自己的。
<com.example.view.PercentRelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.example.percent_relativelayout_dn"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="测试百分比布局"
android:layout_centerInParent="true"
app:layout_widthPercent = "0.5"
app:layout_heightPercent = "0.5"
android:background="#00ff00"
android:id="@+id/textview"
/>
</com.example.view.PercentRelativeLayout>
六,实现与总结
直接在activity中运行测试,是不是很完美了。宽高半分比布局OK了。
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
五大布局都可以实现,今天只是分享了RelativieLayout的中控件的百分百自适应。之前在github上面看了一个很全面的百分百布局方案,其实原理就这样。
欢迎交流,杜乾,Dusan,Q 291902259。