自定义控件,上图下字的Button,图片任意指定大小

来源:互联网 发布:java可以多继承吗 编辑:程序博客网 时间:2024/05/17 07:43

最近处在安卓培训期,把自己的所学写成博客和大家分享一下,今天学的是这个自定义控件,上图下字的Button安卓自带,但是苦于无法设置图片大小(可以在代码修改),今天自己做了一个,首先看一下效果图,比较实用的应该是最后一种样式,第一个按钮添加了点击事件,第二个按钮添加了动画效果。

点击事件正常执行
动画正常执行

知识点

先说一下以前使用android:drawableTop=”“时候修改图片大小的方法:

        //Parameter.IMG_SMALL是图片的大小值,setCompoundDrawables参数指定图片的位置:左、上、右、下        btn.setCompoundDrawables(                null,                findImgAsSquare(InformActivity.this,                R.mipmap.order_forpay, Parameter.IMG_SMALL),                null,                null);    /**     * 获取,寻找并裁剪图片     *     * @param context     * @param id 图片Id     * @return     */    public static Drawable findImgAsSquare(Context context, int id, int sidedp) {        Drawable drawable = ContextCompat.getDrawable(context, id);        int px = ViewHelper.dip2px(context, sidedp);        drawable.setBounds(0, 0, px, px);        return drawable;    }    /**     * 将dip或dp值转换为px值,保证尺寸大小不变     *     * @param context 上下文     * @param dipValue dp的值     * @return     */    public static int dip2px(Context context, float dipValue) {        final float scale = context.getResources().getDisplayMetrics().density;        return (int) (dipValue * scale + 0.5f);    }

自定义属性XML配置
在res/values包下新建attrs.xml文件,配置完attrs.xml文件之后,R文件自动生成对应参数,用于自定义控件的Java类使用,我这里添加了4个,也就是说生成了4个与之对应的参数,比如:drawable_hight生成的参数是:MyImgButton_drawable_hight,用户在xml文件中设置的drawable_hight的属性值最终会通过MyImgButton_drawable_hight返回。
attrs.xml添加如下参数:

    <declare-styleable name="MyImgButton">        <attr name="drawable_hight" format="reference|dimension"></attr>        <attr name="drawable_width" format="reference|dimension"></attr>        <attr name="drawable_space" format="reference|dimension"></attr>        <attr name="myDrawableTop" format="reference|integer"></attr>    </declare-styleable>

format的可选参数类型:

  • “reference” //引用
  • “color” //颜色
  • “boolean” //布尔值
  • “dimension” //尺寸值
  • “float” //浮点值
  • “integer” //整型值
  • “string” //字符串
  • “fraction” //百分数,比如200%

布局XML文件头文件设置
使用自定义控件属性的时候,在Xml布局文件头中需要添加下面一段话,android studio下输入app可以默认生成,不必手动指定,有强迫症也可以将”app”可以替换为任意字母。
xmlns:app=”http://schemas.android.com/apk/res-auto”

布局XML文件引用自定义属性
在Xml布局调用自定义属性的时候,不再是”android:drawable_hight”,而是”app:drawable_hight”,前面的”app”取决于之前头文件的设置。

            app:drawable_hight="40dp"            app:drawable_space="40dp"            app:drawable_width="40dp"            app:myDrawableTop="@drawable/main_home_no"

getMeasuredHeight()和getHeight()的区别
本次代码使用到getMeasuredHeight()方法,用于获取view的真实大小。
当屏幕可以包裹内容的时候,他们的值相等,只有当view超出屏幕后,才能看出他们的区别:getMeasuredHeight()是实际View的大小,与屏幕无关,而getHeight的大小此时则是屏幕的大小。getMeasuredHeight() 等于 getHeight()加上屏幕之外没有显示的大小。

TypedArray
关于获取xml属性值的方法有很多,个人比较喜欢这个,代码相对简洁,先获取TypedArray对象,再通过该对象逐个获取参数值, typedArray.getResourceId()前面一个参数是编辑attrs.xml自动生成的,后面一个是默认值,建议将默认值加入到配置文件中,或者设置为常量,便于以后修改。

 TypedArray typedArray = context.obtainStyledAttributes(attributeSet,                R.styleable.MyImgButton); typedArray.getResourceId(                R.styleable.MyImgButton_myDrawableTop, 0);

onDraw(Canvas canvas)
重写这个方法,通过Canvas对象重新绘制背景图片,配合画笔,可以制作更加复杂的控件。

关于我的自定义控件:

自定义了4个属性:
- drawable_space:图片到顶部的间距,文字到中心线的额外间距
- myDrawableTop:图片资源Id,与原先的background属性不冲突
- drawable_width:图片宽度
- drawable_hight:图片高度

重要参数:一定要指定textSize,代码中将View的高度被设置为textSize的3倍,纯粹是因为测试了很多次感觉这个比例最好看,使用方便,不需要特地去算view的高度。
存在问题:所有按钮是按照最开始的状态底部对齐,这是因为在Java代码中重新设置了控件大小,但是没有重新设置对齐的关系;控件的高度始终是textSize的3倍,并且无法被改变。解决办法就是将代码中关于设置View大小的那两行代码删除,然后手动设置android:layout_height,这里就不做演示。

自定义控件的Java类:

import android.content.Context;import android.content.res.TypedArray;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.Matrix;import android.util.AttributeSet;import android.widget.Button;/** * Created by ChenSS on 2016/9/20. */public class MyImgButton extends Button {    private float mDrawableWidth;    private float mDrawableHight;    private float mDrawableSpace;    private Bitmap mBitmap;    private float mTxtSize;    public MyImgButton(Context context) {        super(context, null);    }    public MyImgButton(Context context, AttributeSet attributeSet) {        super(context, attributeSet);        this.init(context, attributeSet);    }    public void init(Context context, AttributeSet attributeSet) {        //获取所需的控件参数        TypedArray typedArray = context.obtainStyledAttributes(attributeSet,                R.styleable.MyImgButton);        int imgId = typedArray.getResourceId(                R.styleable.MyImgButton_myDrawableTop, 0);        //如果没指定img直接返回        if (imgId == 0)            return;        mTxtSize = this.getTextSize();        //可以考虑将默认值设置到配置文件中        mDrawableSpace = typedArray.getDimension(                R.styleable.MyImgButton_drawable_space, 0);        mDrawableHight = typedArray.getDimension(                R.styleable.MyImgButton_drawable_hight, mTxtSize*2);        mDrawableWidth = typedArray.getDimension(                R.styleable.MyImgButton_drawable_width, mTxtSize*2);        //获得位图        mBitmap = BitmapFactory.decodeResource(getResources(), imgId);        //下面两行可以考虑删除,然后手动设置android:layout_height        //重新定义View的高度,图片高度+3倍的文本高度,这样设置个人感觉很不错,mDrawableSpace是额外指定的高度        this.setHeight((int) (mTxtSize * 3 + mDrawableSpace * 2 + mDrawableHight));        //虽然知道这个时候getMeasuredWidth()的值是0,还是设置一下        this.setWidth(getMeasuredWidth());    }    /***     * 图片的缩放方法     *     * @param bgimage   :源图片资源     * @param newWidth  :缩放后宽度     * @param newHeight :缩放后高度     * @return     */    public static Bitmap zoomImage(Bitmap bgimage, double newWidth,                                   double newHeight) {        // 获取这个图片的宽和高        float width = bgimage.getWidth();        float height = bgimage.getHeight();        // 创建操作图片用的matrix对象        Matrix matrix = new Matrix();        // 计算宽高缩放率        float scaleWidth = ((float) newWidth) / width;        float scaleHeight = ((float) newHeight) / height;        // 缩放图片动作        matrix.postScale(scaleWidth, scaleHeight);        Bitmap bitmap = Bitmap.createBitmap(bgimage, 0, 0, (int) width,                (int) height, matrix, true);        return bitmap;    }    @Override    protected void onDraw(Canvas canvas) {        //缩放位图,不要在setImg方法中使用这个方法        Bitmap b = zoomImage(mBitmap, mDrawableWidth, mDrawableHight);        // 图片顶部居中显示        int x = (int) ((this.getMeasuredWidth() - b.getWidth()) * 0.5);        //y轴设置,默认顶部留一个文本大小的空白        int y = (int) (mTxtSize + mDrawableSpace);        canvas.drawBitmap(b, x, y, null);        // 文本的坐标需要转换,因为默认情况下Button中的文字居中显示,y轴指定0        x = 0;        // 这里需要让文字在底部显示        y = (int) ((this.getMeasuredHeight() / 2) - mTxtSize - mDrawableSpace);        canvas.translate(x, y);        super.onDraw(canvas);    }}

测试用Activity,这里添加了3个按钮,分别添加了点击事件和动画效果:

public class PersonView extends AppCompatActivity implements View.OnClickListener {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_person_view);        this.init();    }    public void init() {        MyImgButton btn1 = (MyImgButton) findViewById(R.id.person_view_btn_1);        MyImgButton btn2 = (MyImgButton) findViewById(R.id.person_view_btn_2);        MyImgButton btn3 = (MyImgButton) findViewById(R.id.person_view_btn_3);        btn1.setOnClickListener(this);        btn2.setOnClickListener(this);        btn3.setOnClickListener(this);    }    @Override    public void onClick(View view) {        switch (view.getId()) {            case R.id.person_view_btn_1:                Toast.makeText(PersonView.this, "点击了按钮", Toast.LENGTH_SHORT).show();                break;            case R.id.person_view_btn_2:                this.rotateyY(view);                break;            case R.id.person_view_btn_3:                break;        }    }    /**     * 图标沿着x轴中心旋转     *     * @param view     */    public void rotateyY(View view) {        ObjectAnimator                .ofFloat(view, "rotationY", 0.0F, 360.0F)                .setDuration(3000)                .start();    }}

Xml布局文件:

<?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:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:background="#FFF"    tools:context="main.com.example.administrator.mydemo.animation.PersonView">    <LinearLayout        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:orientation="horizontal">        <main.com.example.administrator.mydemo.animation.MyImgButton            android:id="@+id/person_view_btn_1"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="hello"            android:textColor="#000000"            android:textSize="15dp"            app:drawable_hight="40dp"            app:drawable_width="40dp"            app:myDrawableTop="@drawable/main_home_no" />        <main.com.example.administrator.mydemo.animation.MyImgButton            android:id="@+id/person_view_btn_2"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="hello"            android:textColor="#000000"            android:textSize="15dp"            app:drawable_hight="40dp"            app:drawable_space="40dp"            app:drawable_width="40dp"            app:myDrawableTop="@drawable/main_home_no" />        <main.com.example.administrator.mydemo.animation.MyImgButton            style="@style/Base.Widget.AppCompat.Button.Borderless"            android:background="#FFF"            android:id="@+id/person_view_btn_3"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="hello"            android:textColor="#000000"            app:myDrawableTop="@drawable/main_home_no" />    </LinearLayout></LinearLayout>
0 0
原创粉丝点击