对于从来没有接触过自定义控件的初学者来说,自定义控件可能不是那么容易,其实有的时候自定义控件并不是那么难,学习这件事本来就是从易到难的,从小学的a、o、e到今年高考的阅读理解《一种美味》是吧;又比如从小学的a、b、c、d到高中的外国天书,唉,不说了,说多了都是泪,恨死了什么李白啊、牛顿啊、阿基米德啊一些不是人的人,害的我们现在只能放弃学文化跑过来撸码,唉,不说了,宫大大(隔壁PHP牛逼同事),给我点纸,擦擦快到嘴里的鼻涕眼泪。扯远了啊,说了这么多,学习没有捷径,努力吧,骚年们!
开始入正题啊,我们都知道Android的自定义控件共有三种,一种:完全自定义,就是继承我们伟大的View类,一点一点测量、摆放、绘制;二种:组合控件;三种:继承一个Android中已有的控件类来进行功能的更改或扩展,也是我今天要说的一种。
在开发中,对于一个Button,有的时候设计只给了我们一张背景图片,而产品又要我们实现这个Button的点击效果怎么办呢,当然你可以再去找设计给你出一张或者自己用PS改改颜色,都可以。通往盛产大片岛国的路千千万,游过去、飞过去都能行。今天我提供一种通过自定义控件实现单张图片点击效果的方式供大家参考,仅供参考啊。
首先我们创建一个java文件继承自Button,因为我们要对Button进行扩展嘛。实现相关构造方法,代码如下:
public class HaveClickEffectButton extends android.support.v7.widget.AppCompatButton {
public HaveClickEffectButton(Context context) {
super(context);
}
public HaveClickEffectButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public HaveClickEffectButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
然后,因为我们要再点击效果上边做事情,所以我们就去实现它的onTouchEvent(MotionEvent event)方法,这个方法跟大家解释一下,这个方法是Android事件分发过程中一个很重要的方法,它的作用就是处理事件,像LongClick事件、Click事件都是在这个方法中触发的,对于Android的事件分发机制不清楚的可以看一下我的这篇文章,我对Android的事件分发机制从Activiy到Window再到ViewGrop最终到达View做了详细的总结。我们重写onTouchEvent(MotionEvent event)方法做什么呢,先来看一下代码:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
if (isEnabled())
setViewAlpha();
break;
case MotionEvent.ACTION_CANCEL:
clearViewAlpha();
break;
case MotionEvent.ACTION_UP:
if (isEnabled())
performClick();
clearViewAlpha();
break;
}
return true;
}
分析一下这段代码,大神绕过啊,我捕获了三中常用的MotionEvent状态,及MotionEvent.ACTION_DOWN 、MotionEvent.ACTION_CANCEL 、MotionEvent.ACTION_UP ,首先当我们点击一个按钮时首先触发DOWN事件 ,我们先判断了一下当前控件是否可用,不可用不做任何处理,如果可用,我去做setViewAlpha()操作,见名知意,这个方法就是设置当前View的透明度,看一下代码:
private void setViewAlpha() {
setAlpha(0.8f);
}
很简单,不解释,将当前View的透明度设置为原来的80%。然后当我们手指移动的时候会执行多次MotionEvent.ACTION_MOVE 但是我们不用管,跟当前功能没关系,这里提一下,当我们移出当前View的时候,控件便会执行MotionEvent.ACTION_CANCEL 事件,那么我们需要处理这个事件,如果我们不处理就会出现问题,就是我们的透明度在在DOWN时改变了,我们必须恢复,所以在这个事件我们需要进行背景的恢复,所以调用了clearViewAlpha();方法,看一下实现:
private void clearViewAlpha() {
setAlpha(1f);
}
我们还要处理一种状态就是用户正常点击事件时的case MotionEvent.ACTION_UP事件 ,在这个事件中我们除了要恢复View的透明度外还要去触发View的点击事件,及调用系统的performClick()方法,到这里我们的自定义View就算是完成了,让我们试一下吧,看看效果,我们在XML布局文件中创建我们的View,如下:
<?xml version="1.0" encoding="utf-8"?>
<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="com.jason.mybuttondemo.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:orientation="horizontal">
<com.jason.mybuttondemo.HaveClickEffectButton
android:id="@+id/btn_cancel_order"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/btn_cancel_order"
android:text="取消订单"
android:textColor="@android:color/white"
android:textSize="15dp" />
<com.jason.mybuttondemo.HaveClickEffectButton
android:id="@+id/btn_print_order"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@drawable/print_order"
android:text="打印订单"
android:textColor="@android:color/white"
android:textSize="15dp" />
</LinearLayout>
</RelativeLayout>
重点是第一个控件的android:background属性我们设置的为selector文件,里边设置了两种不同状态下要显示的图片,如下:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/cancel_order_noclick" android:state_enabled="false" />
<item android:drawable="@drawable/cancel_order" />
</selector>
第二个设置的是单张图片,并不是selector文件,首先我们不管状态,直接在Activity中绑定:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HaveClickEffectButton btn_cancel_order= (HaveClickEffectButton) findViewById(R.id.btn_cancel_order);
HaveClickEffectButton btn_print_order= (HaveClickEffectButton) findViewById(R.id.btn_print_order);
}
}
运行看一下效果:
然后我们在代码中将取消订单按钮的enable状态置为false,看一下效果:
可以看到我们设置的selector文件功能效果出来了,按钮的点击效果没了,显示了我们禁用按钮的背景。
我把整个View的代码都贴出来:
package com.jason.mybuttondemo;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* @Explain:只设计一张背景图就有点击效果的View;
* @Author:LYL
* @Version:V2.0
* @Time:2017/6/9/12:17
*/
public class HaveClickEffectButton extends android.support.v7.widget.AppCompatButton {
public HaveClickEffectButton(Context context) {
super(context);
}
public HaveClickEffectButton(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public HaveClickEffectButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
if (isEnabled())
setViewAlpha();
break;
case MotionEvent.ACTION_CANCEL:
clearViewAlpha();
break;
case MotionEvent.ACTION_UP:
if (isEnabled())
performClick();
clearViewAlpha();
break;
}
return true;
}
private void setViewAlpha() {
setAlpha(0.8f);
}
private void clearViewAlpha() {
setAlpha(1f);
}
}
到这里,我今天要说的东西就说完了,一个很简单的东西,你是不是对自定义控件有了新的认识呢。