Android定制组件的三种方式

2024-06-18 02:18

本文主要是介绍Android定制组件的三种方式,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址: http://www.cnblogs.com/baihai/archive/2012/08/20/2647533.html

方式一、继承原有的组件

实例:带图像的TextView

1、IconTextView.java

复制代码
package net.blogjava.mobile.widget;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.TextView;public class IconTextView extends TextView
{//  命名空间的值private final String namespace = "http://net.blogjava.mobile";//  图像资源IDprivate int resourceId = 0;private Bitmap bitmap;//构造函数public IconTextView(Context context, AttributeSet attrs){//继承TextView的构造函数public TextView(Context context, AttributeSet attrs)super(context, attrs);resourceId = attrs.getAttributeResourceValue(namespace, "iconSrc", 0);if (resourceId > 0)bitmap = BitmapFactory.decodeResource(getResources(), resourceId);}@Overrideprotected void onDraw(Canvas canvas){if (bitmap != null){            //  从原图上截取图像的区域,在本例中为整个图像Rect src = new Rect();//  将截取的图像复制到bitmap上的目标区域,在本例中与复制区域相同Rect target = new Rect();src.left = 0;src.top = 0;src.right = bitmap.getWidth();src.bottom = bitmap.getHeight();int textHeight = (int) getTextSize();target.left = 0;//  计算图像复制到目录区域的纵坐标。由于TextView中文本内容并不是从最顶端开始绘制的,因此,需要重新计算绘制图像的纵坐标target.top = (int) ((getMeasuredHeight() - getTextSize()) / 2) + 1;target.bottom = target.top + textHeight;//  为了保证图像不变形,需要根据图像高度重新计算图像的宽度target.right = (int) (textHeight * (bitmap.getWidth() / (float) bitmap.getHeight()));//  开始绘制图像
            canvas.drawBitmap(bitmap, src, target, getPaint());//  将TextView中的文本向右移动一定的距离(在本例中移动了图像宽度加2个象素点的位置)    canvas.translate(target.right + 2, 0);}super.onDraw(canvas);// 必须最后调用}
}
复制代码

2、main.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:mobile="http://net.blogjava.mobile" android:orientation="vertical"android:layout_width="fill_parent" android:layout_height="fill_parent"><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第一个笑脸" mobile:iconSrc="@drawable/small" /><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第二个笑脸" android:textSize="24dp" mobile:iconSrc="@drawable/small" /><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第三个笑脸" android:textSize="36dp" mobile:iconSrc="@drawable/small" /><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第四个笑脸" android:textSize="48dp" mobile:iconSrc="@drawable/small" /><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第五个笑脸" android:textSize="36dp" mobile:iconSrc="@drawable/small" /><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第六个笑脸" android:textSize="24dp" mobile:iconSrc="@drawable/small" /><net.blogjava.mobile.widget.IconTextViewandroid:layout_width="fill_parent" android:layout_height="wrap_content"android:text="第七个笑脸" mobile:iconSrc="@drawable/small" /></LinearLayout>  
复制代码

3、效果

 

方式二、组合原有的组件

实例:带文本标签的EditText

1、LabelEditText.java

复制代码
package net.blogjava.mobile.widget;import net.blogjava.mobile.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;public class LabelEditText extends LinearLayout {private TextView textView;private String labelText;private int labelFontSize;private String labelPosition;public LabelEditText(Context context, AttributeSet attrs) {super(context, attrs);// 读取labelText属性的资源IDint resourceId = attrs.getAttributeResourceValue(null, "labelText", 0);// 未获得资源ID,继续读取属性值if (resourceId == 0)labelText = attrs.getAttributeValue(null, "labelText");// 从资源文件中获得labelText属性的值elselabelText = getResources().getString(resourceId);// 如果按两种方式都未获得labelTex属性的值,表示未设置该属性,抛出异常if (labelText == null) {throw new RuntimeException("必须设置labelText属性.");}// 获得labelFontSize属性的资源IDresourceId = attrs.getAttributeResourceValue(null, "labelFontSize", 0);// 继续读取labelFontSize属性的值,如果未设置该属性,将属性值设为14if (resourceId == 0)labelFontSize = attrs.getAttributeIntValue(null, "labelFontSize", 14);// 从资源文件中获得labelFontSize属性的值elselabelFontSize = getResources().getInteger(resourceId);// 获得labelPosition属性的资源IDresourceId = attrs.getAttributeResourceValue(null, "labelPosition", 0);// 继续读取labelPosition属性的值if (resourceId == 0)labelPosition = attrs.getAttributeValue(null, "labelPosition");// 从资源文件中获得labelPosition属性的值elselabelPosition = getResources().getString(resourceId);// 如果未设置labelPosition属性值,将该属性值设为leftif (labelPosition == null)labelPosition = "left";String infService = Context.LAYOUT_INFLATER_SERVICE;LayoutInflater li;// 获得LAYOUT_INFLATER_SERVICE服务li = (LayoutInflater) context.getSystemService(infService);LinearLayout linearLayout = null;// 根据labelPosition属性的值装载不同的布局文件if ("left".equals(labelPosition))linearLayout = (LinearLayout) li.inflate(R.layout.labeledittext_horizontal, this);else if ("top".equals(labelPosition))linearLayout = (LinearLayout) li.inflate(R.layout.labeledittext_vertical, this);elsethrow new RuntimeException("labelPosition属性的值只能是left或top.");// 下面的代码从相应的布局文件中获得了TextView对象,并根据LabelTextView的属性值设置TextView的属性textView = (TextView) findViewById(R.id.textview);textView.setTextSize((float) labelFontSize);textView.setText(labelText);}}
复制代码

2、main.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><TextViewandroid:id="@+id/textView"/><net.blogjava.mobile.widget.LabelEditTextandroid:id="@+id/first"android:layout_width="fill_parent"android:layout_height="wrap_content"labelFontSize="16"labelPosition="left"labelText="姓名:" /><net.blogjava.mobile.widget.LabelEditTextandroid:id="@+id/second"android:layout_width="fill_parent"android:layout_height="wrap_content"android:layout_marginTop="20dp"labelFontSize="26"labelPosition="top"labelText="兴趣爱好" /></LinearLayout>
复制代码

3、labeledittext_horizontal.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="horizontal" android:layout_width="fill_parent"android:layout_height="fill_parent"><TextView android:id="@+id/textview" android:layout_width="wrap_content"android:layout_height="wrap_content" /><EditText android:id="@+id/edittext" android:layout_width="fill_parent"android:layout_height="wrap_content" />
</LinearLayout>
复制代码

4、labeledittext_vertical.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical" android:layout_width="fill_parent"android:layout_height="fill_parent"><TextView android:id="@+id/textview" android:layout_width="wrap_content"android:layout_height="wrap_content" /><EditText android:id="@+id/edittext" android:layout_width="fill_parent"android:layout_height="wrap_content" />
</LinearLayout>
复制代码

5、效果

 

方式三、完全重写组件

实例:更换变盘指针后的时钟

1、HandClocl.java

复制代码
package net.blogjava.mobile.widget;import java.util.Calendar;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;public class HandClock extends View implements Runnable {private int clockImageResourceId;private Bitmap bitmap;private float scale;private float handCenterWidthScale;private float handCenterHeightScale;private int minuteHandSize;private int hourHandSize;private Handler handler = new Handler();public void run() {// 重新绘制View
        invalidate();// 重新设置定时器,在60秒后调用run方法handler.postDelayed(this, 60 * 1000);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 根据图像的实际大小等比例设置View的大小setMeasuredDimension((int) (bitmap.getWidth() * scale), (int) (bitmap.getHeight() * scale));}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint paint = new Paint();paint.setAntiAlias(true);Rect src = new Rect();Rect target = new Rect();src.left = 0;src.top = 0;src.right = bitmap.getWidth();src.bottom = bitmap.getHeight();target.left = 0;target.top = 0;target.bottom = (int) (src.bottom * scale);target.right = (int) (src.right * scale);// 画表盘图像
        canvas.drawBitmap(bitmap, src, target, paint);// 计算表盘中心点的横纵坐标float centerX = bitmap.getWidth() * scale * handCenterWidthScale;float centerY = bitmap.getHeight() * scale * handCenterHeightScale;// 表表盘中心点画一个半径为5的实心圆圈canvas.drawCircle(centerX, centerY, 5, paint);// 设置分针为3个象素粗paint.setStrokeWidth(3);Calendar calendar = Calendar.getInstance();int currentMinute = calendar.get(Calendar.MINUTE);int currentHour = calendar.get(Calendar.HOUR);// 计算分针和时间的角度double minuteRadian = Math.toRadians((360 - ((currentMinute * 6) - 90)) % 360);double hourRadian = Math.toRadians((360 - ((currentHour * 30) - 90)) % 360 - (30 * currentMinute / 60));// 在表盘上画分针canvas.drawLine(centerX, centerY, (int) (centerX + minuteHandSize * Math.cos(minuteRadian)), (int) (centerY - minuteHandSize * Math.sin(minuteRadian)), paint);// 设置实针为4个象素粗paint.setStrokeWidth(4);// 在表盘上画分针canvas.drawLine(centerX, centerY, (int) (centerX + hourHandSize * Math.cos(hourRadian)), (int) (centerY - hourHandSize * Math.sin(hourRadian)), paint);}public HandClock(Context context, AttributeSet attrs) {super(context, attrs);// 读取相应的属性值clockImageResourceId = attrs.getAttributeResourceValue(null, "clockImageSrc", 0);if (clockImageResourceId > 0)bitmap = BitmapFactory.decodeResource(getResources(), clockImageResourceId);scale = attrs.getAttributeFloatValue(null, "scale", 1);handCenterWidthScale = attrs.getAttributeFloatValue(null, "handCenterWidthScale", bitmap.getWidth() / 2);handCenterHeightScale = attrs.getAttributeFloatValue(null, "handCenterHeightScale", bitmap.getHeight() / 2);// 在读取分针和时针长度后,将其值按图像的缩放比例进行缩放minuteHandSize = (int) (attrs.getAttributeIntValue(null, "minuteHandSize", 0) * scale);hourHandSize = (int) (attrs.getAttributeIntValue(null, "hourHandSize", 0) * scale);int currentSecond = Calendar.getInstance().get(Calendar.SECOND);// 将定时器设在0分时执行run方法handler.postDelayed(this, (60 - currentSecond) * 1000);}@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();// 删除回调类handler.removeCallbacks(this);}}
复制代码

完整代码:http://pan.baidu.com/share/link?shareid=22336&uk=1829692564

这篇关于Android定制组件的三种方式的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1071033

相关文章

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

springboot项目打jar制作成镜像并指定配置文件位置方式

《springboot项目打jar制作成镜像并指定配置文件位置方式》:本文主要介绍springboot项目打jar制作成镜像并指定配置文件位置方式,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录一、上传jar到服务器二、编写dockerfile三、新建对应配置文件所存放的数据卷目录四、将配置文

Java继承映射的三种使用方法示例

《Java继承映射的三种使用方法示例》继承在Java中扮演着重要的角色,它允许我们创建一个类(子类),该类继承另一个类(父类)的所有属性和方法,:本文主要介绍Java继承映射的三种使用方法示例,需... 目录前言一、单表继承(Single Table Inheritance)1-1、原理1-2、使用方法1-

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

gitlab安装及邮箱配置和常用使用方式

《gitlab安装及邮箱配置和常用使用方式》:本文主要介绍gitlab安装及邮箱配置和常用使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1.安装GitLab2.配置GitLab邮件服务3.GitLab的账号注册邮箱验证及其分组4.gitlab分支和标签的

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

苹果macOS 26 Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色

《苹果macOS26Tahoe主题功能大升级:可定制图标/高亮文本/文件夹颜色》在整体系统设计方面,macOS26采用了全新的玻璃质感视觉风格,应用于Dock栏、应用图标以及桌面小部件等多个界面... 科技媒体 MACRumors 昨日(6 月 13 日)发布博文,报道称在 macOS 26 Tahoe 中

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

python判断文件是否存在常用的几种方式

《python判断文件是否存在常用的几种方式》在Python中我们在读写文件之前,首先要做的事情就是判断文件是否存在,否则很容易发生错误的情况,:本文主要介绍python判断文件是否存在常用的几种... 目录1. 使用 os.path.exists()2. 使用 os.path.isfile()3. 使用