Andriod下完全自定义控件和在自定义控件中使用自定义属性
来源:互联网 发布:java培训有哪些骗局 编辑:程序博客网 时间:2024/05/18 02:45
首先,自定义控件分为三类:
自定义的组合控件
继承View的自定义控件
继承ViewGroup的自定义控件
在这里,我要写的是第二种,也就是继承自View的自定义控件,第一种自定义的组合控件,我已经写过了,可以在我的博客中可以找到
现在来看一下继承View的自定义控件
首先,需要写一个类继承自View,那么,它也有三个构造方法,有一个参数的构造方法实在代码中new这个自定义控件时被调用;有两个参数的构造方法是在布局中使用这个自定义控件的时候调用,有三个参数的构造方法,实在使用到这个自定义控件的样式时被调用;同样,用到那个就重写那个
其次,需要重写onMeasure()方法和onDraw()方法
onMeasure()方法是为了测量控件自己的宽高,onDraw()方法是为了绘制的内容,如果你继承的是ViewGroup,那么你还需要重写onLayout()方法
最后,实现业务逻辑
在这里,我实现的是一个开关的效果
如下图:
这是可以滑动和点击的
自定义属性的步骤,具体请参考我的自定义的组合控件,哪里已经做了详细说明
1、先自定义一个类继承View
// 在代码中创建控件 public MyButton(Context context) { super(context); } // 控件使用在xml布局文件中 public MyButton(Context context, AttributeSet attrs) { super(context, attrs); } // 使用样式时 public MyButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
接下来,你需要在布局中使用这个控件,用全类名
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:abc="http://schemas.android.com/apk/res/com.abc.togglestate" android:layout_width="match_parent" android:layout_height="match_parent" > <com.wdj.togglestate.ui.MyButton android:id="@+id/mybutton" android:layout_width="match_parent" android:layout_height="match_parent" abc:state="false" abc:backgroundRes="@drawable/switch_background" abc:slideButtonRes="@drawable/slide_button_background" /></RelativeLayout>
2、重写onMeasure()方法
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //把背景图片的宽高作为控件的宽高 setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight()); }
3、重写onDraw()方法
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mSwitchBackground, 0, 0, null); if(!isTouching){ //根据当前状态滑动图片 int left = 0; if(currentToggleState){ //如果是打开状态,左边距等于背景的宽度-滑块的宽度 left = mSwitchBackground.getWidth() - mSlideButton.getWidth(); }else { //关闭状态 left = 0; } canvas.drawBitmap(mSlideButton, left, 0, null); }else{ //根据手指触摸的位置,绘制滑动的图片 int left = currentX - mSlideButton.getWidth() / 2; //为了让用户感觉手在图片中间滑动 if(left < 0){ //图片超出左边界,直接绘制到0位置 left = 0; }else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){ //图片超出右边界,直接绘制到右边 left = mSwitchBackground.getWidth() - mSlideButton.getWidth(); } canvas.drawBitmap(mSlideButton, left, 0, null); } }
接下来就是处理自己的业务逻辑
在这里,我把代码全部放在这里了,这是MyButton .java
public class MyButton extends View { private Bitmap mSwitchBackground; private Bitmap mSlideButton; private boolean currentToggleState; //记录当前开关的状态 private int currentX; private boolean isTouching = false; //记录当前控件是否处于触摸中 private MyButtonOnStateChangedListener listener; private String namespace = "http://schemas.android.com/apk/res/com.abc.togglestate"; /** * 在代码中创建控件调用 * @param context, */ public MyButton(Context context) { super(context); } /** * 控件使用在xml布局中使用 * @param context * @param attrs */ public MyButton(Context context, AttributeSet attrs) { super(context, attrs); //获取布局文件中的属性 int backgroundRes = attrs.getAttributeResourceValue(namespace, "backgroundRes",0); setBackgroundRes(backgroundRes); int slideButtonRes = attrs.getAttributeResourceValue(namespace, "slideButtonRes", 0); setSlidButtonBackgroundRes(slideButtonRes); currentToggleState = attrs.getAttributeBooleanValue(namespace, "state", false); } /** * 使用样式时调用 * @param context * @param attrs * @param defStyle */ public MyButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } /** * 测量自己的宽高 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //把背景图片的宽高作为控件的宽高 setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight()); } /** * 绘制内容 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(mSwitchBackground, 0, 0, null); if(!isTouching){ //根据当前状态滑动图片 int left = 0; if(currentToggleState){ //如果是打开状态,左边距等于背景的宽度-滑块的宽度 left = mSwitchBackground.getWidth() - mSlideButton.getWidth(); }else { //关闭状态 left = 0; } canvas.drawBitmap(mSlideButton, left, 0, null); }else{ //根据手指触摸的位置,绘制滑动的图片 int left = currentX - mSlideButton.getWidth() / 2; //为了让用户感觉手在图片中间滑动 if(left < 0){ //图片超出左边界,直接绘制到0位置 left = 0; }else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){ //图片超出右边界,直接绘制到右边 left = mSwitchBackground.getWidth() - mSlideButton.getWidth(); } canvas.drawBitmap(mSlideButton, left, 0, null); } } /** * 给控件设置背景图片 * @param switchBackground */ public void setBackgroundRes(int switchBackground) { mSwitchBackground = BitmapFactory.decodeResource(getResources(),switchBackground); } /** * 给控件设置滑块 * @param slideButtonBackground */ public void setSlidButtonBackgroundRes(int slideButtonBackground) { mSlideButton = BitmapFactory.decodeResource(getResources(), slideButtonBackground); } /** * 开关的状态(这里没有用到) * 用于外部调用 * @param toggleState */ public void isState(boolean toggleState) { currentToggleState = toggleState; } /** * 处理触摸事件 * 触摸后,获取当前的触摸位置,根据位置,更新控件 */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isTouching = true; currentX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: currentX = (int) event.getX(); break; case MotionEvent.ACTION_UP: isTouching = false; currentX = (int) event.getX(); //手抬起后,更改当前控件的状态,根据当前手触摸的 位置和背景图片的中间值进行比较 boolean tempState = currentX >= mSwitchBackground.getWidth() / 2; //6.3、判断当前的状态是否发生变化 if(tempState != currentToggleState){ currentToggleState = tempState; if(listener != null){ listener.OnStateChanged(currentToggleState); } } break; } invalidate(); //重新绘制控件,自动触发onDraw(在主线程中绘制控件) //postInvalidate(); //重新绘制控件,自动触发onDraw(在子线程中绘制控件) return true; //自己消费事件 } //6.1、对外提供开关监听 public interface MyButtonOnStateChangedListener{ public void OnStateChanged(boolean state); } //6.2、让外界把监听器传进来 public void setMyButtonOnStateChangedListener(MyButtonOnStateChangedListener listener){ this.listener = listener; }}
MainActivity.java代码如下
public class MainActivity extends Activity { private MyButton mybutton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mybutton = (MyButton) findViewById(R.id.mybutton); mybutton.setMyButtonOnStateChangedListener(new MyButtonOnStateChangedListener() { @Override public void OnStateChanged(boolean state) { //出来开关状态业务发生变化 Toast.makeText(getApplicationContext(), "" + state, 0).show(); } }); }}
希望能对看到这篇博客的小伙伴有所帮助,仅供大家参考
2 0
- Andriod下完全自定义控件和在自定义控件中使用自定义属性
- 自定义组合控件和在自定义控件中使用自定义属性
- 自定义控件中使用属性
- 自定义控件和自定义属性
- 自定义控件中属性
- [Andriod]自定义控件一
- 自定义控件----自定义属性
- 在用户控件中自定义属性
- 属性动画在自定义控件中的使用
- 如何在styles.xml中使用控件自定义属性
- Android中自定义控件和属性
- android中自定义的控件,使用自定义属性attrs.xml
- 自定义控件:自定义组合控件+自定义属性
- Android简单了解自定义控件和自定义属性如何使用
- Andriod: 在xml布局中使用自定义属性
- Andriod: 在xml布局中使用自定义属性
- Andriod: 在xml布局中使用自定义属性
- Android自定义控件和自定义属性
- 使用setprecision控制输出流显示浮点数的有效数字个数(C++)
- c语言中 结构变量,结构类型标示,结构类型定义的区别
- 安卓版本发布五部曲
- CodeForces Gym 100735B
- Android 自定义View教程(1)
- Andriod下完全自定义控件和在自定义控件中使用自定义属性
- Visual C++
- 蓝桥杯 ADV-193算法提高 盾神与条状项链
- Codeforces Round #206 (Div. 2) C-Vasya and Robot
- 蓝桥杯 ALGO-29 算法训练 校门外的树(区间处理)
- Poj1611 The Suspects 并查集基础题
- hibernate与struts2一起时的异常处理
- 蓝桥杯 ALGO-11算法训练 瓷砖铺放(递归/动态规划)
- [C#]银行家算法的实现