Android 自定义view(1)

Android自定义控件需要一些使用到自定义的属性,我们需要在app\src\main\res\values下新建一个xml文件名字为attrs也就是属性文件,在文件里面我们要使用declare-styleable来声明一个我们自己的格式的一些属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomLayoutHyy">
        <attr name="hyy" format="string"></attr>
        <attr name="ratio" format="float"></attr>
    </declare-styleable>

</resources>

其中属性名根据自定义的含义来命名,也可以根据自己的喜好来命名,总言而之就是根据心情来命名,但是declare-styleable name=”CustomLayoutHyy”里面的name值最好跟我们自定义控件名相同,format就是数据的格式,它有string 、float、boolean、color、dimension、enum、flag、fraction、integer、reference这10种格式,本次只用到float这种格式。该值用来设置图片等比例缩放值,<attr name="hyy" format="string"></attr>只是用来说明属性名是随意起的名字,代码中没有用到。

public class CustomLayoutHyy extends FrameLayout {
    private float ratio;
    public CustomLayout(@NonNull Context context) {
        super(context);
    }

    public CustomLayoutHyy(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
       //拿到自定义的属性值   其中R.styleable.CustomLayout_ratio就是自定义属性radio对应的id, 同理
       //R.styleable.CustomLayout_hyy  就是自定义属性hyy对应的id
        TypedArray ta = context.obtainStyledAttributes(attrs,R.styleable.CustomLayoutHyy);
        ratio = ta.getFloat(R.styleable.CustomLayout_ratio, -1);
        ta.recycle();
    }

    public CustomLayoutHyy(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomLayoutHyy(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);// 获取宽度值
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);// 获取宽度模式
        int height;// 获取高度值
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);// 获取高度模式
        if (widthMode == MeasureSpec.EXACTLY
                && heightMode != MeasureSpec.EXACTLY && ratio > 0) {
            int img_width  = width - getPaddingLeft() - getPaddingRight();
            int img_height  = (int) (img_width / ratio + 0.5f);
            height = img_height  + getPaddingTop() + getPaddingBottom();
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
                    MeasureSpec.EXACTLY);
        }
        // 按照最新的高度测量控件
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:hyy="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >
    <com.example.administrator.viewtest.CustomLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#7f000000"
        android:padding="40dp"
        hyy:ratio="1.7">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@mipmap/ic_launcher"
            />
    </com.example.administrator.viewtest.CustomLayout>

</LinearLayout>

       要实现自定义控件,必须重写onMeasure方法,该方法用来计算控件的宽高,本例中想要使控件的宽度或高度根据所给的比例设置,就需要在此方法中重新进行测量计算。

       onMeasure(int widthMeasureSpec, int heightMeasureSpec)可以看到,该方法有两个参数,widthMeasureSpec其实就是width的宽度值与宽度的模式,heightMeasureSpec就是height的高度值与高度的模式,重写该方法时需要对计算控件的实际大小,然后调用setMeasuredDimension(int, int)设置控件实际大小,在Android中,有三种模式,分别是:MeasureSpec.AT_MOST、MeasureSpec.EXACTLY、MeasureSpec.UNSPECIFIED。我们经常使用的wrap_conten对应的模式为MeasureSpec.AT_MOST,该模式意味着控件大小一般随着控件的子控件或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可,使用的match_parent对应的模式为MeasureSpec.EXACTLY,该模式说明控件的大小为精确值,我们已知的控件大小的时候可以设置此模式。当控件的大小不确定,控件的大小是可以随便变化的时候对应的模式为MeasureSpec.UNSPECIFIED,我们通常使用的父控件为Adapter的就是使用的就是这种模式。

     

猜你喜欢

转载自blog.csdn.net/hy1308060113/article/details/81478320