Android开发进阶自定义控件之滑动开关实现方法【附demo源码下载】_Android

本文实例讲述了Android开发进阶自定义控件之滑动开关实现方法。分享给大家供大家参考,具体如下:

自定义开关控件

Android自定义控件一般有三种方式

1、继承Android固有的控件,在Android原生控件的基础上,进行添加功能和逻辑。

2、继承ViewGroup,这类自定义控件是可以往自己的布局里面添加其他的子控件的。

3、继承View,这类自定义控件没有跟原生的控件有太多的相似的地方,也不需要在自己的肚子里添加其他的子控件。

ToggleView自定义开关控件表征上没有跟Android原生的控件有什么相似的地方,而且在滑动的效果上也没有沿袭Android原生的地方,所以我们的自定义ToggleView选择继承View

同样的自定义控件需要复写三个构造方法

//在布局中使用该控件的时候,而且有额外的style属性的时候调用该构造方法,
public ToggleView(Context context, AttributeSet attrs, int defStyle);
//在布局中使用该控件的时候调用该构造方法
public ToggleView(Context context, AttributeSet attrs)
//在Java代码中直接new该控件的时候,调用该构造方法
public ToggleView(Context context)

因为是自定义的控件,所以属性还是自己定义的比较好用一些。我们这里定义三个属性

1、背景图片
2、滑块的图片
3、布局中默认的开关的状态

所以就需要用到了自定义属性

在values目录下,新建xml文件,attrs.xml

在里面定义自己的属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="toggle">
  <attr name="switchBackground" format="reference" />
  <attr name="slidingBackground" format="reference" />
  <attr name="toggleState" format="boolean" />
 </declare-styleable>
</resources>

<declare-styleable name属性>是可以在R文件中找到该属性名称的

<attr>标签中,一个标签写一个属性 name属性表示属性名称,format表示属性类型

这里定义了三个属性名和属性类型。

属性和自定义控件的三个构造方法已经完成,就我们就可以在布局文件中添加自定义的控件了

<RelativeLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:hss="http://schemas.android.com/apk/res/com.hss.toggle"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 >
 <com.hss.toggle.ToggleView
 android:id="@+id/toggleView"
 android:layout_height="wrap_content"
 android:layout_width="wrap_content"
 android:layout_centerInParent="true"
 hss:switchBackground="@drawable/switch_background"
 hss:slidingBackground="@drawable/slide_button_background"
 hss:toggleState="true"
 >
 </com.hss.toggle.ToggleView>
</RelativeLayout>

注意:在我自定义控件com.hss.toggle.ToggleView中,部分属性是以android开头的,部分属性是以hss(我自己定义的命名空间)开头的,这是为什么呢?

注意看本片代码第二行,

xmlns:hss="http://schemas.android.com/apk/res/com.hss.toggle"

我在这里写着样一行代码,就说明把values/attrs.xml中的每个条目都导入进来了,就可以直接使用我在attrs.xml里面的属性了

可以直接使用自定义的属性之后,问题应该聚焦到怎么在Java代码中获取到我自定义的属性的值呢?

根据命名空间和自定义属性的name值获取,看代码:

String namespace = "http://schemas.android.com/apk/res/com.hss.toggle";
int toggle_switchbackground = attrs.getAttributeResourceValue(namespace, "switchBackground", -1);
int toggle_slidingbackground = attrs.getAttributeResourceValue(namespace, "slidingBackground", -1);
toggle_state = attrs.getAttributeBooleanValue(namespace, "toggleState", false);

看到没?该方法用到了attr参数,所以获取自定义属性值的操作应该在两个参数的那里面执行。

整体的自定义控件的类见代码:

package com.hss.toggle;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
/**
 * 自定义开关控件
 * @author hss
 */
public class ToggleView extends View {
 private static final String TAG = "ToogleView";
 private Bitmap sliding_background;
 private Bitmap switch_background;
 private boolean isSliding = false;
 private boolean toggle_state = false;
 private int downX;
 private mToggleStateChangeListener;
 // 构造方法,在xml文件布局的时候,指定了style的时候调用
 public ToggleView(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 }
 // 构造方法,在xml文件中布局的时候,没有指定style的时候调用
 public ToggleView(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 //在Java代码中 获取到xml中自定义属性对应的值
 String namespace = "http://schemas.android.com/apk/res/com.hss.toggle";
 int toggle_switchbackground = attrs.getAttributeResourceValue(namespace, "switchBackground", -1);
 int toggle_slidingbackground = attrs.getAttributeResourceValue(namespace, "slidingBackground", -1);
 toggle_state = attrs.getAttributeBooleanValue(namespace, "toggleState", false);
 Log.i(TAG,""+toggle_slidingbackground+" "+toggle_switchbackground);
 // 设置自定义开关的图片
 setToggleSwitchBackground(toggle_switchbackground);
 setToggleSlidingBackground(toggle_slidingbackground);
 setToggleState(toggle_state);
 }
 // 构造方法 在代码中new的时候调用
 public ToggleView(Context context) {
 this(context, null);
 }
 /**
 * 给滑动的控件设置背景图片
 *
 * @param toggle_slidingbackground 图片ID
 */
 private void setToggleSlidingBackground(int toggle_slidingbackground) {
 sliding_background = BitmapFactory.decodeResource(getResources(),toggle_slidingbackground);
 }
 /**
 * 给背景的控件,设置背景图片
 *
 * @param toggle_switchbackground 图片ID
 */
 private void setToggleSwitchBackground(int toggle_switchbackground) {
 switch_background = BitmapFactory.decodeResource(getResources(),toggle_switchbackground);
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 //测量控件的大小,设置控件的大小为背景图片的大小
 setMeasuredDimension(switch_background.getWidth(),switch_background.getHeight());
 }
 @Override
 protected void onDraw(Canvas canvas) {
 //开始画自定义控件,使用canvas对象先把背景图片画上来
 canvas.drawBitmap(switch_background, 0, 0, null);
 if (isSliding) {
 //如果是滑动状态
  //控件距离左边的相对距离为:(控件每时每刻的距离自己左上方的焦点的x轴距离)-(控件本身一半的x轴宽度)
  int left = downX - sliding_background.getWidth() / 2;
  //控件最大的滑动距离(距离左边最大的距离)就是:(背景图片的宽度)-(滑块图片的宽度)
  int rightAlign = switch_background.getWidth()- sliding_background.getWidth();
  //如果距离左边的距离小于0,,就不让他继续往左边动了
  if (left < 0) {
  left = 0;
  } else if (left > rightAlign) {
  //如果距离左边的距离》应该距离左边的最大距离,也不让他往右边移动了
  left = rightAlign;
  }
  //控制好属性之后就可以时时刻刻的跟着画了
  canvas.drawBitmap(sliding_background, left, 0, null);
 } else {
  //如果不滑动,则根据控件的属性中开关的状态,来画滑块的位置
  if (toggle_state) {
  //如果开关状态为真,滑块移动到最右边
  int left = switch_background.getWidth() - sliding_background.getWidth();
  canvas.drawBitmap(sliding_background, left, 0, null);
  } else {
  //如果开关状态为假,滑块移动到最左边
  canvas.drawBitmap(sliding_background, 0, 0, null);
  }
 }
 super.onDraw(canvas);
 }
 @Override
 public boolean onTouchEvent(MotionEvent event) {
 //重写触摸事件
 int action = event.getAction();
 switch (action) {
 case MotionEvent.ACTION_DOWN:
  //开始点击的时候,是否滑动置为真,获取到当前手指的距离
  isSliding = true;
  downX = (int) event.getX();
  break;
 case MotionEvent.ACTION_MOVE:
  downX = (int) event.getX();
  break;
 case MotionEvent.ACTION_UP:
  //当点击结束的时候将是否滑动记为假,获取到移动的x轴的坐标
  downX = (int) event.getX();
  isSliding = false;
  //获取到背景图片中间的那个值
  int center = switch_background.getWidth() / 2;
  boolean state = downX > center;
  //如果先后的状态不相同,则将新的状态赋给成员变量,然后调用监听的方法
  if (toggle_state != state) {
  toggle_state = state;
  if (null != mToggleStateChangeListener) {
   mToggleStateChangeListener
    .onToggleState(toggle_state);
  }
  }
  break;
 }
 //调用一次onDraw()方法
 invalidate();
 return true;
 }
 //给自定义开关控件设置监听的方法
 public void setOnToggleStateLinstener(OnToggleStateChangeListener listen){
 mToggleStateChangeListener = listen;
 }
 public void setToggleState(boolean b) {
 toggle_state = b;
 }
 //监听回调接口,方法由实现接口的类实现
 public interface OnToggleStateChangeListener {
 public void onToggleState(boolean state);
 }
}

到此,我们的自定义控件部分的逻辑就写完了,,借下来再MainActivity中调用一下

package com.hss.toggle;
import android.app.Activity;
import android.os.Bundle;
import com.hss.toggle.ToggleView.OnToggleStateChangeListener;
import com.hss.toggle.utils.ToastUtil;
public class MainActivity extends Activity{
 private ToggleView toggleView;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 // TODO Auto-generated method stub
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 toggleView = (ToggleView) findViewById(R.id.toggleView);
 toggleView.setOnToggleStateLinstener(new OnToggleStateChangeListener() {
  @Override
  public void onToggleState(boolean state) {
  showToast(state);
  }
 });
 }
 //这里调用到的自己封装的一个快速弹Toast的工具类
 private void showToast(boolean state) {
 ToastUtil.makeSuddenlyToast(getApplicationContext(), state?"开":"关");
 }
}

ToastUtil类如下:

package com.hss.toggle.utils;
import android.content.Context;
import android.widget.Toast;
/**
 * @title Toast工具类
 * @author hss
 */
public class ToastUtil {
 private static Toast toast;
 /**
 * 弹出短时间Toast
 * @param context 上下文对象
 * @param text 要弹出的文字
 */
 public static void makeShortToast(Context context,String text){
 toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
 toast.show();
 }
 /**
 * 弹出长时间的Toast
 * @param context 上下文对象
 * @param text 要弹出的文字
 */
 public static void makeLongToast(Context context,String text){
 toast = Toast.makeText(context, text, Toast.LENGTH_LONG);
 toast.show();
 }
 /**
 * 单例Toast
 * @param context 上下文对象
 * @param text 要弹出的文字
 */
 public static void makeSuddenlyToast(Context context,String text){
 if(toast==null){
  toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
 }
 toast.setText(text);
 toast.show();
 }
}

总结一下,其实本次自定义控件的步骤如下:

1、在values/attrs.xml自定义属性和属性值的数据类型

2、在Java代码中定义自定义控件类,继承View或者ViewGroup或者Android原生的控件,实现构造方法,获取到自定义属性的值,并且编写对应的逻辑和点击事件。

3、在布局文件中使用自定义控件和自定义属性(注意命名空间)。

4、在MainActivity中调用

完整实例代码点击此处本站下载

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android控件用法总结》、《Android视图View技巧总结》、《Android操作SQLite数据库技巧总结》、《Android操作json格式数据技巧总结》、《Android数据库操作技巧总结》、《Android文件操作技巧汇总》、《Android编程开发之SD卡操作方法汇总》、《Android开发入门与进阶教程》及《Android资源操作技巧汇总》

希望本文所述对大家Android程序设计有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, 自定义控件
滑动开关
自定义控件demo、wpf 自定义控件 源码、微信小程序demo源码、swift demo 源码、three.js实现demo源码,以便于您获取更多的相关知识。

时间: 2024-09-10 12:26:44

Android开发进阶自定义控件之滑动开关实现方法【附demo源码下载】_Android的相关文章

Android编程滑动效果之倒影效果实现方法(附demo源码下载)_Android

本文实例讲述了Android编程滑动效果之倒影效果实现方法.分享给大家供大家参考,具体如下: 前面介绍了使用<Android编程实现3D滑动旋转效果的方法>,现在介绍图片倒影实现,先看效果图 这里主要通过自定义Gallery和ImageAdapter(继承自BaseAdapter)实现 1.倒影绘制 ImageAdapter继承自BaseAdapter,详细实现可见前面关于Android Gallery的用法.这里重点介绍倒影原理及实现 倒影原理: 倒影效果是主要由原图+间距+倒影三部分组成,

Android编程实现可滑动的开关效果(附demo源码下载)_Android

本文实例讲述了Android编程实现可滑动的开关效果.分享给大家供大家参考,具体如下: 闲着没事,把之前写的一个Demo放上来分享下.就是一个开关,实现可滑动和动画效果.不是图片切换. 好了,先上图: 完整实例代码点击此处本站下载. 直接把自定义的这个View代码放上来,有注释应该很好理解: 首先是布局: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android=&qu

Android仿英语流利说取词放大控件的实现方法(附demo源码下载)_Android

本文实例讲述了Android仿英语流利说取词放大控件的实现方法.分享给大家供大家参考,具体如下: 1 取词放大控件 英语流利说是一款非常帮的口语学习app,在app的修炼页面长按屏幕,会弹出一个放大镜,当手指移到某个单词的附近,可以看到该英文单词会被选中,效果如下图所示: 2 代码示例 该控件挺有意思,于是我写了个简单的demo,完整实例代码点击此处本站下载.,程序运行后的效果如下: 3 实现原理 该控件的实现原理比较简单,下面介绍几个比较重要的类 ① WordView 在实习该控件的过程中,我

Android TreeView效果实现方法(附demo源码下载)_Android

本文实例讲述了Android TreeView效果实现方法.分享给大家供大家参考,具体如下: 应该说很多的操作系统上面都提供了TreeView空间,实现树形结构,这个树形结构的应用时很广泛的,而Google开发Android的时候出于Android手机是触摸屏幕的考虑,用手指操作树形结构很不方便,从这方面考虑没有提供TreeView的空间,而是只是提供了一个ExpandableListView:android中的二级树型Widget,虽然已经能满足不少的功能需求,例如书签的功能就可以使用这个控件

Android编程实现手绘及保存为图片的方法(附demo源码下载)_Android

本文实例讲述了Android编程实现手绘及保存为图片的方法.分享给大家供大家参考,具体如下: 运行效果图预览: 应 yzuo_08 要求做了此Demo,跟以前那个手写板Demo不同的是可以将画布的内容保存为图片. 附上关键代码: MainView.java package com.tszy.views; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; impor

Android开发之在程序中时时获取logcat日志信息的方法(附demo源码下载)_Android

本文实例讲述了Android开发之在程序中时时获取logcat日志信息的方法.分享给大家供大家参考,具体如下: 今天分享一个在软件开发中很实用的例子,也是这几天在通宵加班中我使用的一个小例子, 在程序中监听Log信息. 为什么说它实用?原因是Android的开发厂商各种修改之后手机和手机之间以后存在很多差异.比如说魅族M9手机 开发中如果项目中涉及到访问手机系统的地方,例如访问系统短信库,M9手机它会提示一个dialog框 让用户自己去选择 访问还是不访问.这样就给开发适配带来了巨大的麻烦.本来

Android AutoCompleteTextView连接数据库自动提示的方法(附demo源码下载)_Android

本文实例讲述了Android AutoCompleteTextView连接数据库自动提示的方法.分享给大家供大家参考,具体如下: 这个简单例子也体现MVC的思想.AutoCompleteTextView 就是View,而SimpleCursorAdapter就是Controller,SQLiteOpenHelper就相当于Model. 1.首先定义MVC中的Model,自定义DBHelper类继承SQLiteOpenHelper用于访问数据库 import android.content.Con

Android重写TextView实现文字整齐排版的方法(附demo源码下载)_Android

本文实例讲述了Android重写TextView实现文字整齐排版的方法.分享给大家供大家参考,具体如下: XRTextView类 package rong.android.test; import org.json.JSONArray; import org.json.JSONException; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; impor

Android编程滑动效果之倒影效果实现方法(附demo源码下载)

本文实例讲述了Android编程滑动效果之倒影效果实现方法.分享给大家供大家参考,具体如下: 前面介绍了使用<Android编程实现3D滑动旋转效果的方法>,现在介绍图片倒影实现,先看效果图 这里主要通过自定义Gallery和ImageAdapter(继承自BaseAdapter)实现 1.倒影绘制 ImageAdapter继承自BaseAdapter,详细实现可见前面关于Android Gallery的用法.这里重点介绍倒影原理及实现 倒影原理: 倒影效果是主要由原图+间距+倒影三部分组成,