zoukankan      html  css  js  c++  java
  • 自定义控件如同系统控件:自定义控件,画空间图片,定义空间属性,构造监听器。

      android的基本控件很难满足用户的需求,因此有时候用户需要根据美工设置的一些图片来自定义一些控件,不多说,现在介绍一下,自定义一个开关控件的流程,让大家更了解控件的工作原理:

    1、首先构建一个控件的类,继承view,这时候需要覆写view的构造方法。同时需要把美工美化好的图片拖到drawable目录下。在控件初始化的时候需要加载进美工的图片即:背景bg和开关滑动钮swicher。注意加载图片时候R.drawable时候有2个注意别选错了,否则找不到图片的id。

    2、android的控件都是通过view下的Ondraw()方法画上去的,因此要覆写view的Oncreate方法将bg和swicher画上去。画画需要画纸和笔,因此在初始化的时候构建一支笔,画板系统提供,即参数里的canvas.里面的参数分别是图、上,左的坐标和笔。因此我们要设定的就是画的位置就是上左的坐标即可。

    3、这时候我们可以在xml文件里可以添加这个控件看看效果了,注意添加空间时候一定加上包名和类名(不要带上class如:<com.example.togglebutton.ui.MytoggleButton即可,同时在最上面加上控件的命名空间:复制android的,并将android改成这个程序的包名即可。注意的是,默认下控件大小是屏幕的长宽,因此需要调用onMeasure()方法测量宽高和setMeasuredDimension()重新设定宽高。

    4、为了让空间可以拖动,就必须覆写view的onTouchEvent()方法,注意所有的触摸事件的方法都是由这个方法来处理的,然后监听:落下、滑动、离开这3个动作(想更复杂的也可以监听别的事件),通过打印发现只能监听到“落下”的事件,原来这个方法默认是系统处理的,若想用户自己处理就必须将return surper.onTouchEvent()修改成return true;(ps:当你的控件继承其他的具体控件时候,若继承的空间有自己的监听器接口时候,这里就不能改为true,并且已经可监听到,因为继承的控件已经覆写了View的OntouchEvent事件了,若该为true时候继承的操作就失效了)。

    5、设定事件处理,我们根据ondraw方法画图,里设定坐标时候将左设定为类的成员变量,上为0,因此当我们改变left的值,然后调用invalidate()刷新操作调用ondraw()方法来重新画图即可。

    6、设定控件的属性,这里就添加一个状态state当作事例,首先在values里创建一个xml文件,然后在xml文件里声明、定义属性atrrs。如果大家不记得就可以参考安装的sdk目录下android自带属性的定义:sdkplatformsandroid-19data esvaluesattrs.xml。并且在构造方法:public MytoggleButton(Context context, AttributeSet attrs)里解析属性,好在配置文件中使用属性,并且里面设置默认属性值。

    7、在类里给出设定state和得到state的函数,并将state作为函数的成员变量。

    8、给空间设定监听事件,这里就定义一个监听state发生改变的接口,在接口里声明state发生变化的方法。然后将接口作为类的成员变量,为类设定一个设置监听器的函数,将接口作为参数,因此设置监听器必须实现这个接口,然后把实现额接口复制给类成员变量。

    9在ontouchEvent()的up里先判断状态是否改变,若改变就利用实例化了接口的类来调用接口的onchange方法就完成了状态放生改变的监听事件。

    下面给出完整的demo:

    main.xml文件

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:myview="http://schemas.android.com/apk/res/com.example.togglebutton.ui"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.example.togglebutton.MainActivity$PlaceholderFragment"
        android:background="#ffff00"
         >
    
        <com.example.togglebutton.ui.MytoggleButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            myview:state="true"
            android:id="@+id/togglebutton"
           />
        <TextView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/text"
          	android:layout_centerVertical="true"
          	android:layout_centerHorizontal="true"
            
            />
    
    </RelativeLayout>
    

      values 下的属性定义文件atrrs.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
    <declare-styleable name="myview">
       <attr name="state" format="boolean" />
         </declare-styleable>
    </resources>
    

      开关控件类的定义

    package com.example.togglebutton.ui;
    
    import com.example.togglebutton.R;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.drawable.BitmapDrawable;
    import android.text.Editable.Factory;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    public class MytoggleButton extends View {
    	private Context context; 
    	private Bitmap bg;
    	private Bitmap sw;
    	private Paint paint;
    	private  int maxleft;
    	private int left;
    	private  boolean state;
    	
    	private OnMytoggleButtonStateChangeLitener onMytoggleButtonStateChangeLitener;
    	
    	public void setOnMytoggleButtonStateChangeLitener(OnMytoggleButtonStateChangeLitener l)
    	{
    		onMytoggleButtonStateChangeLitener=l;
    	}
    	
    	
    	public MytoggleButton(Context context) {
    		super(context);
    		this.context=context;
    		init();
    	}
    
    	//这里是解析属性的AttributeSet attrs,可以在配置文件中使用这些属性
    	public MytoggleButton(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		this.context=context;	
    		init();
    		//解析属性
    		String namespace="http://schemas.android.com/apk/res/com.example.togglebutton";
    		state=attrs.getAttributeBooleanValue(namespace, "state", true);//默认为关
    		if(state==false)
    			left=0;
    		else
    			left=maxleft;
    		
    	}
    
    	public MytoggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
    		super(context, attrs, defStyleAttr);
    		this.context=context;	
    		init();
    		}
    	//初始化
    	public void init()
    	{
    		 paint=new Paint();
    		 sw=BitmapFactory.decodeResource(getResources(), R.drawable.slide_button_background);
    		 bg=BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
    		 maxleft=bg.getWidth()-sw.getWidth();
    	}
    
    	public void setState(boolean state)
    	{
    		if(state=true)
    			{
    			left=maxleft;
    			state=true;
    			}
    		else 
    			{
    			state=false;
    			left=0;
    			}
    		invalidate();
    	}
    	public boolean getState()
    	{
    		return state;
    	}
    	
    	@Override//这是空间开始创建时会运行一次
    	protected void onDraw(Canvas canvas) {
    		
    		canvas.drawBitmap(bg, 0, 0, paint);
    		canvas.drawBitmap(sw, left, 0,paint);
    		super.onDraw(canvas);
    		
    	}
    
    	
    	
    	
    	@Override//限制空间高宽
    	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    		setMeasuredDimension(bg.getWidth(), bg.getHeight());
    	}
    
    	int startX=0;
    	int currentX=0;
    	@Override
    	public boolean onTouchEvent(MotionEvent event) {
    		
    	
    		
    		switch (event.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			startX=(int) event.getX();
    			System.out.println("down"+state);
    			break;
    		case MotionEvent.ACTION_MOVE:
    			currentX=(int) event.getX();
    			int d=currentX-startX;
    			left=d+left;
    			if(left>=maxleft)
    				left=maxleft;
    			else if(left<=0)
    				left=0;
    			System.out.println("move"+state);
    			break;
    		case MotionEvent.ACTION_UP:
    			boolean stateOlder=state;
    			System.out.println("up"+state);
    			if(left>maxleft/2)
    			{
    				left=maxleft;
    				state=true;
    				}
    			else
    			{
    				left=0;
    				state=false;
    				}
    			
    			if(state!=stateOlder&&onMytoggleButtonStateChangeLitener!=null)
    				onMytoggleButtonStateChangeLitener.stateChange(getState());
    			
    			break;
    
    		default:
    			break;
    		}
    	
    		invalidate();//刷新画图,调用空间的ondrow()方法
    		return true;//super.onTouchEvent(event);
    	}
    	
    	
    }
    

      activity文件:

    public class MainActivity extends Activity {
    
    	private MytoggleButton togglebutton;
    	private TextView tx;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        	
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
           
            togglebutton=(MytoggleButton) findViewById(R.id.togglebutton);
            tx=(TextView) findViewById(R.id.text);
            tx.setText("State:"+(togglebutton.getState()?"开":"关"));
            togglebutton.setOnMytoggleButtonStateChangeLitener(new OnMytoggleButtonStateChangeLitener(){
    
    			@Override
    			public void stateChange(boolean state) {
    				 tx.setText("State:"+(togglebutton.getState()?"开":"关"));
    			}
            }
            		);
            
        }
    }
    

      

  • 相关阅读:
    Mac 升级后 Git报错处理
    iOS 进制转换(十进制转62进制)
    转:基于IOS上MDM技术相关资料整理及汇总
    NPM ERR! 403 403 Forbidden 问题处理
    Rxjs学习,结合angular(搁置,后续还会添加)
    如何快速关联/修改Git远程仓库地址
    VUE 路由守卫 next() / next({ ...to, replace: true }) / next(‘/‘) 说明
    chrome developer tools 的一個 bug
    IBM MQ 2035错误
    tp5 gateway 报错 stream_socket_client(): unable to connect to tcp://127.0.0.1:1236 (Connection refused)
  • 原文地址:https://www.cnblogs.com/bokeofzp/p/4768760.html
Copyright © 2011-2022 走看看