自定义控件(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;
    }

}

自此,一个自定义按钮就完成了,最终效果如下:

时间: 2024-12-20 19:20:17

自定义控件(1)-点击实现开关按钮切换的相关文章

JavaScript点击div来回切换两个颜色及两张图片切换的方法

点击div切换颜色的代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> .test1{ width:100px; height: 100px; background-color: green; } </style> <

C# DataGridView点击Enter键切换单元格

#region 将ENTER键转换为TAB protected override void OnKeyUp(System.Windows.Forms.KeyEventArgs e) { base.OnKeyUp(e); if (e.KeyCode == System.Windows.Forms.Keys.Enter) { e.Handled = true; System.Windows.Forms.SendKeys.Send("{TAB}"); } } protected overri

极简的js点击组图切换效果

程序员进行前端开发时,时常要用到点击切换组图的动画效果,网上确实有很多此类插件,但是都很麻烦,乌糟糟无数代码,有那个看的时间,自己都能把功能写完了.在这里我提供一段极简的js点击组图切换效果代码,包含一个html文件,一个css文件,一个js文件,一个jquery.js文件,以及一张图片. index.html <html><head><title>js点击组图左右滑动</title><meta http-equiv="Content-Typ

基于jquery鼠标点击图片翻开切换效果

基于jquery鼠标点击图片翻开切换效果是一款基于jQuery+CSS3实现的点击图片切换特效.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div class="container"> <img src="images/1.jpeg" alt="1" /> <img src="images/2.jpeg" alt="2" /> <img s

Android自定义控件系列三:自定义开关按钮(三)--- 自定义属性

尊重原创,转载请注明出处:http://blog.csdn.net/cyp331203/article/details/40855377 接之前的:Android自定义控件系列二:自定义开关按钮(一)和Android自定义控件系列三:自定义开关按钮(二)继续,今天要讲的就是如何在自定义控件中使用自定义属性,实际上这里有两种方法,一种是配合XML属性资源文件的方式,另一种是不需要XML资源文件的方式:下面我们分别来看看: 一.配合XML属性资源文件来使用自定义属性: 那么还是针对我们之前写的自定义

基于HTML5鼠标点击淡入淡出切换代码

基于HTML5鼠标点击淡入淡出切换代码.这是一款基于jQuery+HTML5实现的淡入淡出切换全屏幻灯片代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <header id="immortal_header"> <div id="immortal_carousel" class="carousel thumbnail_text_carousel_fade thumbnail_text_carousel_wrapp

使用jQuery实现点击左右滑动切换特效

使用jQuery实现点击左右滑动切换特效: HTML代码如下: 1 <!--整体背景div--> 2 <div class="warp"> 3 <!--中间内容div--> 4 <div class="divContent"> 5 <div class="content"> 6 <ul class="contentUl"> 7 <li> 8 &

echats点击旋转并切换高亮效果

echats点击旋转并切换高亮效果 本方法前面是点击旋转,原理是每次点击是重新渲染图表,计算图标旋转角度,达到切换旋转效果, 本方法后面是点击切换图标时该扇形显示高亮效果 onChartClick(param) { //切换图标时计算角度 let dataIndex = param.dataIndex; let angle = 0; //计算起始扇形角度 if (dataIndex == 0) { this.radarOptionConfig.series[0].startAngle = thi

图形化编程娱乐于教,点击角色,切换背景

跟很多学生聊过,很多学生不是不努力,只是找不到感觉.有一点不可否认,同样在一个教室上课,同样是一个老师讲授,学习效果迥然不同.关键的问题在于,带入感,我能给出的建议,就是咬咬牙,坚持住,没有学不会的知识.会陆续分享图形化编程的经验,希望能够做成一个专题.如果您觉得有用,就给点个赞吧.涉及的软件包括scratch3.0 (.sb3).Python.Kittenblock. 程序解读:点击角色,切换背景 知识点:运动,控制,循环控制,外观 涉及的软件:scratch3.0 (.sb3).Python