自定义控件---继承View类方式(自定义开关效果案例)

----------------------------------------------------简单的效果图--------------------------------------------------------------------------

activity_main.xml

<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"
    tools:context=".MainActivity" >

    <com.atguigu.mytogglebutton.MyToggleView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        />

</RelativeLayout>

MainActivity.java

package com.atguigu.mytogglebutton;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
}

MyToggleView.java

package com.atguigu.mytogglebutton;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

/**
 * 设置滑动效果
 * 1、 手指按下记录坐标
 * 2、来到新坐标记录下
 * 3、计算偏移量
 * 4、依据偏移量移动按钮
 * 5、屏蔽非法值
 * 6、重新初始化初始值
 */
public class MyToggleView extends View implements View.OnClickListener {
	// true:开的状态 false:关闭状态(默认关闭状态)
	private boolean isOpened = false;

	// 画笔-辅助工具
	private Paint paint;

	// 背景图片
	private Bitmap backgroudbitmap;
	private Bitmap slidingbitmap;
	// 滑动按钮距离左边的距离
	private float sledingLeft;
	// 滑动按钮距离左边的最大距离
	private float maxLeft;

	/**
	 * 自定义控件的构造方法--带样式
	 */
	public MyToggleView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initView();
	}

	/**
	 * 系统规定,在布局文件使用View,实例化的时候只用带有两个参数的构造方法
	 */
	public MyToggleView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initView();
	}

	/**
	 * 通常在代码中实例化的时候使用
	 */
	public MyToggleView(Context context) {
		super(context);
		initView();
	}

	/**
	 * 初始化View
	 */
	private void initView() {
		// 创建画笔
		paint = new Paint();
		// 设置抗锯齿
		paint.setAntiAlias(true);
		// 创建背景图片
		backgroudbitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.switch_background);
		slidingbitmap = BitmapFactory.decodeResource(getResources(),
				R.drawable.slide_button);
		// 滑动按钮距离左边的最大距离
		maxLeft = backgroudbitmap.getWidth() - slidingbitmap.getWidth();
		// 设置点击事件
		MyToggleView.this.setOnClickListener(this);

	}

	/**
	 * 执行的主要方法:
	 * 1.构造
	 * 2.测量-onMeasure();一般是View的时候测量
	 * 3.指定view的大小和位置:onLayout();
	 * 一般View用不到,但是如果当前View继承的是ViewGroup,一定要实现,有义务指定孩子的位置和大小。
	 * 4.绘制-onDraw();
	 * 5、onTouchEvent()
	 */

	/**
	 * 1.View本身大小多少,这由onMeasure()决定;
	 * 2.View在ViewGroup中的位置如何,这由onLayout()决定
	 * 3.绘制View,onDraw()定义了如何绘制这个View
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 指定大小
		setMeasuredDimension(backgroudbitmap.getWidth(),
				backgroudbitmap.getHeight());
	}

	/**
	 * 绘制
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		// canvas.drawBitmap(bitmap, left, top, paint)左上坐标(从左上顶点开始画)
		canvas.drawBitmap(backgroudbitmap, 0, 0, paint);
		canvas.drawBitmap(slidingbitmap, sledingLeft, 0, paint);
	}

	// 起始的X轴的坐标
	private float startX;

	// 历史的X轴的坐标
	private float lastX;

	/**
	 * true:点击事件生效触摸事件不生效 false:点击事件不生效,触摸事件生效
	 */
	private boolean isClickEnbale = false;

	/**
	 * 触摸事件
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		super.onTouchEvent(event);
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:// 按下
			// 1.手指按下的坐标
			lastX = startX = event.getX();
			// 手指按下时,设置状态为点击事件生效,触摸事件不生效
			isClickEnbale = true;
			break;
		case MotionEvent.ACTION_MOVE:// 滑动
			// 2.来到新的坐标
			float newX = event.getX();

			// 3.计算偏移量
			float distanceX = newX - startX;

			// 从开始到现在滑动的距离
			if (Math.abs(newX - lastX) > 5) {
				// 如果偏移量大于5,设状态为点击事件失效,触摸事件生效
				isClickEnbale = false;
			}
			// 重新绘制界面
			flunshView(distanceX);

			// 5.重新记录初始值
			startX = event.getX();

			break;

		case MotionEvent.ACTION_UP:// 离开
			// 如果触摸事件生效,点击事件失效
			if (!isClickEnbale) {
				// 如果滑动按钮距离左边的距离大于滑动按钮距离左边最大距离的一半,就设置状态为开
				if (sledingLeft > maxLeft / 2) {
					isOpened = true;
				} else if (sledingLeft <= maxLeft / 2) {
					// 如果滑动按钮距离左边的距离小于滑动按钮距离左边最大距离的一半,就设置状态为关
					isOpened = false;
				}
				// 重新绘制界面
				flushViewState();

			}
			break;

		default:
			break;
		}
		return true;
	}

	/**
	 * 屏蔽非法值和根据位置重新绘制
	 */
	private void flunshView(float distanceX) {
		sledingLeft += distanceX;
		if (sledingLeft < 0) {
			sledingLeft = 0;
		}

		if (sledingLeft > maxLeft) {
			sledingLeft = maxLeft;
		}

		// 4.根据最新的位置绘制
		invalidate();
	}

	/**
	 * 点击事件
	 */
	@Override
	public void onClick(View v) {
		// 如果是点击状态生效,触摸事件失效
		if (isClickEnbale) {
			flushViewState();
			// 点击后,如果是状态时开的话就设置为关,如果是关的状态就设置为开
			isOpened = !isOpened;
		}
	}

	private void flushViewState() {
		// 开的状态
		if (isOpened) {
			// 开的状态
			sledingLeft = maxLeft;
		} else {
			// 关的状态
			sledingLeft = 0;
		}

		invalidate();// 在主线程中执行 导致onDraw执行
	}

}
时间: 2024-10-26 00:32:56

自定义控件---继承View类方式(自定义开关效果案例)的相关文章

自定义控件---继承View类方式(五彩绚烂的水波纹案例)

---------------------------------------看效果(还有动画效果哦)---------------------------------------------------- activity_main.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"

Android自定义View之圆环交替 等待效果

学习了前面两篇的知识,对于本篇实现的效果,相信大家都不会感觉太困难,我要实现的效果是什么样呢?下面请先看效果图: 看上去是不很炫的样子,它的实现上也不是很复杂,重点在与onDraw()方法的绘制. 首先是我们的attrs文件: <?xml version="1.0" encoding="utf-8"?> <resources> <attr name="firstColor" format="color&qu

Android查缺补漏(View篇)--自定义 View 的基本流程

View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以形成丰富多彩的交互界面,一个应用中界面交互的体验往往在应用的受欢迎程度上起了很关键得作用,所以开发者们大多会想方设法的做出一个更加精美的界面,例如:通过自定义View.深入学习View的原理以便更好的对其优化使其在操作起来更加流畅等等,也正因为如此,在面试中View也常常作为面试官重点考察的对象之一

多线程三:显示主线程执行的效果-第一种继承方式 继承Thread类

首先看下一个最简单的例子 继承Thread类 覆盖run方法

自定义控件基础01_菜单轮__viewPager_下拉框_自定义开关

1,自定义控件分类: 1.1组合控件:由安卓中原生的控件组合起来,配合动画达成的效果 1.2自定义控件 1.3组合控件案例演示: 案例:优酷菜单demo 三层圆环,按下menu键会通过动画效果消失在界面,点击小房子和中层圆环,最外层圆环消失 ①布局实现: 三层相对布局相互叠加(因为图片背景是透明的,所以可以叠加显示) 由于三个布局是叠加显示的,所以这个菜单选项要使用一个占据焦点比较强的(不然有可能点击不到)ImageButton控件 控件上background=”@android:color/t

自定义控件之直接继承View创建全新视图(二)

自定义控件我们上一节探讨了一种最简单的自定义是直接继承View的子类,实现控件的不同UI视图展示及功能的拓展,在学习新知识前可以温习下之前所学知识-自定义控件之对现有控件拓展(一). ok,在回顾了之前所学的知识之后,现在我们来学习稍微复杂点的自定义控件:今天我们实现一个直接继承于View的全新控件.大家都知道音乐播放器吧,在点击一首歌进行播放时,通常会有一块区域用于显示音频条,我们今天就来学习下,播放器音频条的实现. 首先我们还是先定义一个类,直接继承于View,并重写它的构造方法,并初始化一

.Net 配置文件——继承ConfigurationSection实现自定义处理类处理自定义配置节点

除了使用继承IConfigurationSectionHandler的方法定义处理自定义节点的类,还可以通过继承ConfigurationSection类实现同样效果. 首先说下.Net配置文件中一个潜规则: 在配置节点时,对于想要进行存储的参数数据,可以采用两种方式:一种是存储到节点的属性中,另一种是存储在节点的文本中. 因为一个节点可以有很多属性,但是只要一个innertext,而要在程序中将这两种形式区分开会带来复杂性. 为了避免这个问题,.net的配置文件只是用属性存储而不使用inner

【Android应用开发技术:用户界面】自定义View类设计

作者:郭孝星 微博:郭孝星的新浪微博 邮箱:[email protected] 博客:http://blog.csdn.net/allenwells Github:https://github.com/AllenWells 设计良好的类总是相似的,它使用一个易用的接口来封装一个特定的功能,它能有效的使用CPU和内存,我们在设计View类时,通常会考虑以下因素: 遵循Android标准规则 提供自定义的风格属性值并能够被Android XML Layout所识别. 发出可访问的事件 能够兼容And

.Net 配置文件--继承ConfigurationSection实现自定义处理类处理自定义配置节点

除了使用继承IConfigurationSectionHandler的方法定义处理自定义节点的类,还可以通过继承ConfigurationSection类实现同样效果. 首先说下.Net配置文件中一个潜规则: 在配置节点时,对于想要进行存储的参数数据,可以采用两种方式:一种是存储到节点的属性中,另一种是存储在节点的文本中. 因为一个节点可以有很多属性,但是只要一个innertext,而要在程序中将这两种形式区分开会带来复杂性. 为了避免这个问题,.net的配置文件只是用属性存储而不使用inner