android自定义控件是作为一名优秀的android攻城狮必不可少的技能,为了进一步认识自定义控件,层次递进的学习,今天给大家以案例(滑动开关案例)的形式说明自定义控件的使用(案例UI图片取自网上图库,在此致谢图片分享者)。
首先晒上案例效果图
(1)通过组合原生的控件,加上一些特殊动画的组合来达到自定义的需求
(2)定义一个类继承View,或者还可以继承ViewGroup
package com.example.toggleview; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class ToggleView extends View { private Bitmap switch_background; private Bitmap slide_button_background; private boolean toggleCurrentState = false; //当前开关的状态 private boolean isSliding = false; //默认不滑动 private int downX; private OnToggleStateChangeListener mToggleStateChangeListener; //直接new 初始化的时候调用 public ToggleView(Context context) { super(context); } public ToggleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } //在布局里面使用的时候调用 public ToggleView(Context context, AttributeSet attrs) { super(context, attrs); String namespace = "http://schemas.android.com/apk/res/com.example.toggleview"; int switchBackground = attrs.getAttributeResourceValue(namespace, "switchBackground", -1); int slidingBackground = attrs.getAttributeResourceValue(namespace, "slidingBackground", -1); //设置开关的状态 toggleCurrentState = attrs.getAttributeBooleanValue(namespace, "toggleState", false); //设置 开关的背景 setToggleBackground(switchBackground); //设置滑动块的背景 setToggleSlidBackGround(slidingBackground); } //设置开关背景 public void setToggleBackground(int switchBackground) { switch_background = BitmapFactory.decodeResource(getResources(), switchBackground); } //设置开关的滑动块 public void setToggleSlidBackGround(int slideButtonBackground) { slide_button_background = BitmapFactory.decodeResource(getResources(),slideButtonBackground); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量当前viwe的宽和高 setMeasuredDimension(switch_background.getWidth(), switch_background.getHeight()); } //绘制内容 被绘制到了当前控件上 @Override protected void onDraw(Canvas canvas) { //[1]画开关的背景 canvas.drawBitmap(switch_background, 0, 0, null); if (isSliding) { //[2]根据当前dwonX 画滑动块 int left = downX - slide_button_background.getWidth()/2; //[2.1]对边界进行处理 int rightAlgin = switch_background.getWidth() - slide_button_background.getWidth(); if (left<0) { left = 0; }else if (left > rightAlgin) { left = rightAlgin; } canvas.drawBitmap(slide_button_background, left, 0, null); }else { //不是滑动状态 根据 当前开关的状态 画 //[2]画滑动块背景 if (toggleCurrentState) { //开关打开状态 int left = switch_background.getWidth() - slide_button_background.getWidth(); canvas.drawBitmap(slide_button_background, left, 0,null); }else { //开关关闭 canvas.drawBitmap(slide_button_background, 0, 0,null); } } super.onDraw(canvas); } @Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: //按下 //[1]获取手指触摸的位置 isSliding = true; downX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: //移动 downX = (int) event.getX(); break; case MotionEvent.ACTION_UP: //抬起 downX = (int) event.getX(); //[0]手指抬起 处于不是滑动状态 isSliding = false; //[1]获取开关背景一半 int center = switch_background.getWidth()/2; boolean state = downX > center; //[1.1]开关的状态没有发生改变的时候 不触发我们写回调事件 if (toggleCurrentState!=state) { toggleCurrentState = state; //[2]触发我们定义的回调方法 if (mToggleStateChangeListener!=null) { mToggleStateChangeListener.onToggleState(toggleCurrentState); } } break; } //当前view 会进行重绘 会调用onDraw invalidate(); //让当前控件处理事件 return true; } //设置开关的状态 public void setToggleState(boolean b) { toggleCurrentState = b; } //设置开关改变的监听 public void setOnToggleStateLinstener(OnToggleStateChangeListener listen){ mToggleStateChangeListener = listen; } //开关滑动接口 public interface OnToggleStateChangeListener{ public void onToggleState(boolean state); } }
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:example="http://schemas.android.com/apk/res/com.example.toggleview" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" > <com.example.toggleview.ToggleView android:id="@+id/toggleView1" android:layout_width="wrap_content" android:layout_height="wrap_content" example:slidingBackground="@drawable/slide_button_background" example:switchBackground="@drawable/switch_background" example:toggleState="true" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="toggleview"> <attr name="switchBackground" format="reference" /> <attr name="slidingBackground" format="reference" /> <attr name="toggleState" format="boolean" /> </declare-styleable> </resources>
package com.example.toggleview; import com.example.toggleview.ToggleView.OnToggleStateChangeListener; import android.os.Bundle; import android.app.Activity; import android.widget.Toast; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //[1]找到我们自己定义的开关控件 ToggleView toggleView = (ToggleView) findViewById(R.id.toggleView1); //[2]设置开关的背景 // toggleView.setToggleBackground(R.drawable.switch_background); //[3]设置开关的滑动块 // toggleView.setToggleSlidBackGround(R.drawable.slide_button_background); //[4]设置开关的状态 // toggleView.setToggleState(false); //[5]设置一个开关状态的监听 toggleView.setOnToggleStateLinstener(new OnToggleStateChangeListener() { @Override public void onToggleState(boolean state) { if (state) { Toast.makeText(getApplicationContext(), "开", 0).show(); //TODO }else{ Toast.makeText(getApplicationContext(), "关", 0).show(); } } }); } }