自定义控件,上图下字的Button,图片任意指定大小
最近处在安卓培训期,把自己的所学写成博客和大家分享一下,今天学的是这个自定义控件,上图下字的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>
自定义控件,上图下字的Button,图片任意指定大小的更多相关文章
- CSS- 控制图片显示指定大小 并超过大小自动缩小
有时候利用css比较方便控制网页html中img图片的显示大小.这样也省得自己一个一个去定义. img,a img{ border:; margin:; padding:; max-width:600 ...
- Linux下删除空文件,删除指定大小的文件
Linux下批量删除空文件(大小等于0的文件)的方法: find . -name "*" -type f -size 0c | xargs -n 1 rm -f 用这个还可以删除指 ...
- iOS 通用button 上图下字
UIButton *first = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, kHeight(80), kHeight(80))]; [firs ...
- python-----opencv读取视频、读取图片 显示指定大小并按键实现暂停、播放
按空格键实现暂停播放,代码如下: cv2.namedWindow("m1", 0) cv2.resizeWindow("m1", 800, 600) cv2.i ...
- Linux下自动清理超过指定大小文件
作者:邓聪聪 扫描某个目录下的文件,发现超过指定大小即清空 1)扫描目录下的文件 2)判断文件大小 3)清空大于指定文件的内容 以byte为单位显示文件大小,然后和20M大小做对比. 20M换算成字节 ...
- android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变
首先要知道 自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置[ ...
- Android下利用Bitmap切割图片
在自己自定义的一个组件中由于需要用图片显示数字编号,而当前图片就只有一张,上面有0-9是个数字,于是不得不考虑将其中一个个的数字切割下来,需要显示什么数字,只需要组合一下就好了. 下面是程序的关键代码 ...
- 两行 CSS 代码实现图片任意颜色赋色技术
很久之前在张鑫旭大大的博客看到过一篇 PNG格式小图标的CSS任意颜色赋色技术,当时惊为天人,感慨还可以这样玩,私底下也曾多次想过有没有其他方法可以实现,又或者不仅仅局限于 PNG 图片. mix-b ...
- NGUI和UGUI图片字 艺术字(Bitmap图片转文字)制作方法
用图片字而不是图片 美术和程序的配合,需要程序能够很快抓住问题重点并提出解决方案.美术出的图片字比我们使用的字体更好好看,那么是否要一个个图片去拼成数字呢? NGUI创建图片字 准备材料 美术提供的数 ...
随机推荐
- win10 uwp 隐私声明
本文讲的是如何去写隐私声明. 垃圾微软要求几乎每个应用都要有隐私声明,当然如果你不拿用户信息的话,那么用户声明是一个URL,我们应该把应用声明放在哪? 其实我们简单方法是把隐私声明Privacy Po ...
- JavaScript命令模式
第一,命令模式: (1)用于消除调用者和接收者之间直接的耦合的模式,并且可以对(调用这个过程进行留痕操作) (2)真的不要乱用这个模式,以为他使你简单调用写法变得非常的复杂和有些难以理解. (3)你的 ...
- 什么是git?window下安装git
一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以 ...
- [译]ASP.NET Core 2.0 网址重定向
问题 如何在ASP.NET Core 2.0中实现网址重定向? 答案 新建一个空项目,在Startup.cs文件中,配置RewriteOptions参数并添加网址重定向中间件(UseRewriter) ...
- TinyOS编程思想和Nesc基础语法
TinyOS操作系统由nesc语言写成,从程序员角度看,它的基本作用就是提供了一组API接口以及一些编程规则. 具体来说,基于nesc语言的TinyOS编程行为具有以下特点: a.兼容C语言:使用ne ...
- 【20171104中】chrome自动刷新网页
target:刷访问量 tools:chrome / url start: s1:百度知道,https://zhidao.baidu.com/question/750134067096113532.h ...
- KICKSTART无人值守安装
1.1 环境说明 [root@test ~]# cat /etc/redhat-release CentOS release 6.9 (Final) [root@test ~]# uname -r - ...
- margin负值的相关应用
1.页面上实现css sprite背景定位效果 其实margin:-40px 0 0 -160px;与background-position:-160px -40px;实现的原理是一致的,而差别就 ...
- js数组遍历some,foreach,map,filter,every对比
1. [...].some(ck)函数 ---- 某个一个为true,则为true 对数组中每个元素执行一次ck函数,知道某个元素返回true,则直接返回true.如果都返回f ...
- Problem C: 求个最大值
class MaxValue { public: vector<int> vec; void append(int n) { vec.push_back(n); } int getMax( ...