回调就是A和B有合作关系,A的某一个环节需要B自己告诉A要怎么做,这就是回调,回调一定有接口。
只要写过自定义控件的,就一定写回调。这个是自然的,本文的意义是为了简单描述对回调的一个理解。
其实做回调很好,比如我们做了一个自定义的进度条,按钮,或者开关等等,我们都需要做回调接口,有什么好处呢?可以让使用我们控件的人自己去选择一些事情,而不是我们写接口的吧东西给写死了,我们可以提供一些方法,让别人自己选择颜色,大小,数值等等。
例子
我们假设做了一个自定义的开关按键,然后按下之后就可以改变一下另外一个控件的文字。(只为演示,不做开关,免得代码偏长)
点击之后调用者要执行一些逻辑,至于具体执行什么逻辑,一点都不关我们事,这是使用我们控件的人自己想干嘛就去干吗。
一个简单自定义控件
/**
* 一个自定义开关按钮(假设),附带set点击的接口
* 第一步,定义接口,接口里面有个 设置点击的监听
* 第二步,在当前类中定义一个接口的变量,以便接受其他类实现接口后传过来的接口
* 第三步,当当前类中写一个 public的设置接口的方法,参数是我们写的接口
* 第四步,在我们的需要的地方执行其他类要求我们做的事情
*/
public class DiyToggle extends View {
private Bitmap mBackground;
// 第二步,在当前类中定义一个接口的变量,以便接受其他类实现接口后传过来的接口
private OnToggleClickListener onToggleClickListener;
public DiyToggle(Context context) {
super(context);
}
public DiyToggle(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DiyToggle(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setBackground(int resId) {
mBackground = BitmapFactory.decodeResource(getResources(), resId);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = mBackground.getWidth();
int measuredHeight = mBackground.getHeight();
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
protected void onDraw(Canvas canvas) {
// 画背景
if (mBackground != null) {
canvas.drawBitmap(mBackground, 0, 0, null);
}
}
// 第三步,当当前类中写一个 public的设置接口的方法,参数是我们写的接口
// 这样其他类一旦调用了setToggleClickListener,就必须实现我们写的接口
public void setToggleClickListener(OnToggleClickListener onToggleClickListener){
if(onToggleClickListener != null){
this.onToggleClickListener = onToggleClickListener;
}
}
// 第一步,定义接口,接口里面有个 设置点击的监听
interface OnToggleClickListener{
void onDoClick();
}
// 第四步,在我们的需要的地方执行其他类要求我们做的事情
// 这里我们复写了系统自带的onTouchEvent的up方法,也就是当点击后松开手指时执行
// 我们在松开手指后,就调用我们自己接口的 onDoClick方法,具体做什么,我们不知道,也不用知道
// 其他人说,我们做就好。
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
if(action==MotionEvent.ACTION_UP){
onToggleClickListener.onDoClick();
}
return true;
}
}
布局文件
<?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.amqr.callbackdemo.MainActivity">
<com.amqr.callbackdemo.DiyToggle
android:id="@+id/mTog"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</com.amqr.callbackdemo.DiyToggle>
<TextView
android:id="@+id/mTvCenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:textSize="30dp"
android:layout_centerInParent="true"
/>
</RelativeLayout>
MainActivity
public class MainActivity extends Activity {
private DiyToggle mTog;
private TextView mTvCenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTog = (DiyToggle) findViewById(R.id.mTog);
mTvCenter = (TextView) findViewById(R.id.mTvCenter);
mTog.setBackground(R.mipmap.tog);
// 调用了DiyToggle的 setToggleClickListener 方法,就得实现 接口
mTog.setToggleClickListener(new DiyToggle.OnToggleClickListener() {
@Override
public void onDoClick() {
Log.d("Tog","...=================");
mTvCenter.setText("世界");
}
});
}
}