android自定义控件(1)-点击实现开关按钮切换
自定义控件的步骤、用到的主要方法:
1、首先需要定义一个类,继承自View;对于继承View的类,会需要实现至少一个构造方法;实际上这里一共有三个构造方法:
public View (Context context)是在java代码创建视图的时候被调用(使用new的方式),如果是从xml填充的视图,就不会调用这个
public View (Context context, AttributeSet attrs)这个是在xml创建但是没有指定style的时候被调用
public View (Context context, AttributeSet attrs, int defStyle)这个是在第二个基础上添加style的时候被调用的
所以对于这里来说,如果不使用style, 我们重点关注第二个构造方法即可
2、对于任何一个控件来说,它需要显示在我们的界面上,那么肯定需要定义它的大小;
在这里Google提供了一个方法:protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec);我们去看这个方法的内部,实际上是调用了
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight);这个方法,其中第一个参数是view的宽,第二个参数是view的高,这样我们就可以设置view的宽高了,但是要注意,这样设置的单位都是像素
3、对于一个需要显示的控件来说,我们往往还需要确定它的位置:
这就要求重写onLayout方法;但是实际上这个方法在自定义view的时候使用的不多,原因是因为对于位置来说,控件只有建议权而没有决定权,决定权一般在父控件那里。
4、对于一个控件,需要显示,我们当然需要将它绘制出来,这里就需要重写onDraw方法,来将这个控件绘制出来
5、当控件状态改变的时候,我们很可能需要刷新view的显示状态,这时候就需要调用invalidate()方法,这个方法实际上会重新调用onDraw方法来重绘控件
6、在定义控件的过程中,如果需要对view设置点击事件,可以直接使用setOnClickListener方法,而不需要写view.setOnClickListener;
7、在布局文件中将这个自定义控件定义出来,注意名字要使用全类名;而且,由于是继承自view控件,所以在xml文件中如果是view本身的属性都可以直接使用,比如android:layout_width等等
这里比较关键的地方就在于这个onDraw方法,我们一起来看一下:
/**
* 画view的方法,绘制当前view的内容
*/
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
Paint paint = new Paint();
// 打开抗锯齿
paint.setAntiAlias(true);
// 画背景
canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
// 画滑块
canvas.drawBitmap(slideButton, slideBtn_left, 0, paint);
}
onDraw方法传入的参数是一个Canvas画布对象,这个实际上跟Java中的差不太多,我们要在画布上画画也需要一个画笔,我们这里也将其初始化出来Paint paint = new Paint(),同时设置了一个抗锯齿效果paint.setAntiAlias(true),然后调用drawBitmap的方法,先后绘制了开关的背景和开关的滑块,分别入下图:


这里要注意的一点就是,drawBitmap(Bitmap bitmap, float left, float top, Paint paint)方法中间的两个float类型的参数,分别代表绘制图形的左上角的x和y的坐标(原点设置在左上角),所以这里如果我们个绘制坐标都传入0,0,那么开关会处在一个关的状态,这里,我们对于滑块使用了一个变量slideBtn_left来设置其位置,那么对于关闭状态,slideBtn_left的值就应该为0,对于开启状态,slideBtn_left的值就应该是backgroundBitmap(背景)的宽度减去slideButton(滑块)的宽度;
下面来看具体的代码,注解比较详细:
自定义控件的类DJSwitch.java,继承自View:
package com.example.test.view;
import com.example.test.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
public class DJSwitch extends View {
/**
* 在代码中创建View的时候,调用的是此构造方法
* 类似于iOS中的initWithFrame方法
* @param context
*/
public DJSwitch(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
/**
* 在XML创建View的时候,调用的是此构造方法
* 类似于iOS中的initWithCoder及awakeFromNib方法
* @param context
* @param attrs
*/
public DJSwitch(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
/** 当前开关状态 */
private boolean currentState = false;
/**
* 初始化View
*/
private void initView() {
/*
* 从资源库中加载一个image对象
* ios UIImage *backgroundImage = [UIImage imageNamed:@"app_switch_bg"];
* 也就是说,android里面的图像实体bitmap,可以当成是ios中的UIImage
* 区别在于,ios中UIImage可以通过类方法来获取,android里面则是通过工厂方法来实现
*/
switch_bg_img = BitmapFactory.decodeResource(getResources(), R.drawable.app_switch_bg);
switch_btn_img = BitmapFactory.decodeResource(getResources(), R.drawable.app_switch_btn);
// 添加监听
setOnClickListener(new MyOnSwitchClickListener()); // 可以理解为ios中的addTarget方法,或addGestureRecognizer
}
private int switchBtnX;
private int switchBtnY;
private Bitmap switch_bg_img;
private Bitmap switch_btn_img;
private class MyOnSwitchClickListener implements OnClickListener {
@Override
public void onClick(View v) {
switchBtnClick();
}
}
/** 当点击时调用此方法 */
private void switchBtnClick() {
currentState = !currentState;
invalidate(); // 类似于ios中[self setNeedDisplay]方法
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 相当于设置这个View的CGSize属性
setMeasuredDimension(switch_bg_img.getWidth(), switch_bg_img.getHeight());
}
/**
* 画View的方法,绘制当前View的内容,类似于ios中的drawRect方法
* ios在绘制时传入的是CGRect这个结构体,android里面传入的是canvas对象
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint(); // 中文意思为油漆,颜料
paint.setAntiAlias(true); // 设置抗锯齿
/**
* 画背景
* Quartz2D中也有类似的API
* UIImage *image = [UIImage imageNamed:@"hhaa"]
* [image drawAtPoint];
* [image drawInRect]; // 将左边的图片放置到右边的矩形框里面,并且拉伸
*/
canvas.drawBitmap(switch_bg_img, 0, 0, paint);
// 画按钮
if (currentState) {
switchBtnX = switch_bg_img.getWidth() - switch_btn_img.getWidth();
} else {
switchBtnX = 0;
}
canvas.drawBitmap(switch_btn_img, switchBtnX, switchBtnY, paint);
}
}
在布局文件中将其定义出来:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<!-- 为了清楚的看见该View的大小及位置,给其定义背景 -->
<com.example.test.view.DJSwitch
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff0000"
android:layout_centerInParent="true"
/>
</RelativeLayout>
这里由于没有写任何点击触发业务的逻辑,只是一个单纯的控件,所以在MainActivity里面没有加入多的代码:
package com.example.test;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
自此,一个自定义按钮就完成了,最终效果如下:


android自定义控件(1)-点击实现开关按钮切换的更多相关文章
- android自定义控件(2)-拖拽实现开关切换
在这里,我们的主要工作就是在原有代码的基础上,增加一个重写的onTouchEvent方法,刚添加上来的时候是这个样子的: @Override public boolean onTouchEvent(M ...
- Android Studio精彩案例(二)《仿微信动态点击底部tab切换Fragment》
转载本专栏文章,请注明出处,尊重原创 .文章博客地址:道龙的博客 现在很多的App要么顶部带有tab,要么就底部带有tab.用户通过点击tab从而切换不同的页面(大部分情况时去切换fragment). ...
- Android自定义控件 开源组件SlidingMenu的项目集成
在实际项目开发中,定制一个菜单,能让用户得到更好的用户体验,诚然菜单的样式各种各样,但是有一种菜单——滑动菜单,是被众多应用广泛使用的.关于这种滑动菜单的实现,我在前面的博文中也介绍了如何自定义去实现 ...
- Android自定义控件之日历控件
标签: android 控件 日历 应用 需求 2015年09月26日 22:21:54 25062人阅读 评论(109) 收藏 举报 分类: Android自定义控件系列(7) 版权声明:转载注 ...
- [C#] (原创)一步一步教你自定义控件——03,SwitchButton(开关按钮)
一.前言 技术没有先进与落后,只有合适与不合适. 本篇的自定义控件是:开关按钮(SwitchButton). 开关按钮非常简单,实现方式也多种多样,比如常见的:使用两张不同的按钮图片,代表开和关,然后 ...
- Android自定义控件之基本原理
前言: 在日常的Android开发中会经常和控件打交道,有时Android提供的控件未必能满足业务的需求,这个时候就需要我们实现自定义一些控件,今天先大致了解一下自定义控件的要求和实现的基本原理. 自 ...
- Android自定义控件1
概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...
- 一起来学习Android自定义控件1
概述 Android已经为我们提供了大量的View供我们使用,但是可能有时候这些组件不能满足我们的需求,这时候就需要自定义控件了.自定义控件对于初学者总是感觉是一种复杂的技术.因为里面涉及到的知识点会 ...
- android自定义控件实现TextView按下后字体颜色改变
今天跟大家分享一下Android自定义控件入门,先介绍一个简单的效果TextView,按下改变字体颜色,后期慢慢扩展更强大的功能 直接看图片 第一张是按下后截的图,功能很简单, ...
随机推荐
- pyhthon --递归,装饰器
递归: 递归的概念很简单,如果函数包含了对其自身的调用,该函数就是递归.拗口一点的定义是,如果一个新的调用能在相同过程中较早的调用结束之前开始,那么该过程就是递归. """ ...
- CA 证书
1.ubuntu curl 命令报错(CA) kamil@vm-ubuntu:~$ curl https://szxyzs.vanke.com/DataCenter/datacenter/api cu ...
- java 中变量的存储与引用
java交换两个变量的值 1.幼儿园版 package tst; public class Test { public static void main(String[] args) { String ...
- asp.net生产环境和开发环境的错误日志包装策略
对于错误日志的输出,我们借助web.config的两个标志位: <!--全局包装异常处理页面,只有在PageError和Application_Error做清除错误操作才可不跳转--> & ...
- linux内核增加系统调用--Beginner‘s guide
Linux内核中设置了一组用于实现系统功能的子程序,称为系统调用.系统调用和普通库函数调用非常相似明知是系统调用由操作系统核心提供,运行于核心态,而普通的函数调用由函数库或用户自己提供,运行于用户态. ...
- 百度地图学习(II)-Android端的定位
哎,经历了小编的最近时间的研究,我的百度定位终于成功啦,刹那间觉得自己萌萌哒啦(- ̄▽ ̄)- 话不多说,直接进入正题: 首先,我们来看一下效果: [分析定位原理] [编码分析] 1)处理程序的清单文件 ...
- [NOIP2012] 提高组 洛谷P1084 疫情控制
题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...
- UVa 7146 Defeat the Enemy(贪心)
题目链接: 传送门 Defeat the Enemy Time Limit: 3000MS Memory Limit: 32768 KB Description Long long ago t ...
- FZU みねちゃんの修罗场(从一堆出现三次的数中找出出现两次的数)
みねちゃんの修罗场 Time Limit: 5000 mSec Memory Limit: 1024 KB Description みねちゃん是个成绩优秀大学二年级学生,本来是和像自己妹妹一般 ...
- CSS--值和单位
等价颜色表 什么叫Web安全色 所谓的“web安全”颜色是指在256色计算机系统上总能避免抖动的颜色. Web安全颜色可以表示为RGB值为20%和51(相应的十六进制值为33)的倍数. 如果使用RGB ...