android 事件分发流程

来源:互联网 发布:ubuntu cp210x 编辑:程序博客网 时间:2024/06/07 05:10

今天整理下android的事件分发流程,在android中,所有控件都继承自View控件,以及View的子控件ViewGroup,今天说的事件分发机制就是以这两个控件来讲解:

在android的UI布局中,通常最低层都是继承自ViewGroup的容器类控件,最顶层的往往是继承自View的显示类控件,由于UI的需求,往往会出现多层容器嵌套的问题,在极端情况下,如果多层容器都需要处理滑动事件的话,就容易引起滑动事件冲突问题,在这里,我就详细分析下android中事件的传递过程,只要明白了事件传递过程,就可以在实际应用中处理好他们之间的冲突关系了。


滑动事件的传递过程在View以及ViewGroup中有些许不同,View中处理滑动事件跟两个方法有关,dispatchTouchEvent和onTouchEvent,ViewGroup是继承自View,除了上述两个方法外,还多了一个方法,就是onInterceptTouchEvent,下面是事件的传递过程:

View : dispatchTouchEvent -> onTouchEvent;

ViewGroup: dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent;


为了清晰明了的分析事件传递过程,我们以实例来说话,下面先定义一个继承自ViewGroup的类,主要就是多了事件传递过程的打印信息,代码如下:

import android.content.Context;import android.util.Log;import android.view.MotionEvent;import android.view.ViewGroup;/** * @author: xiewenliang * @Filename: * @Description: * @date: 2017/4/14 14:18 */public class EventViewGroup extends ViewGroup {    private String TAG;    public EventViewGroup(Context context, String TAG) {        super(context);        this.TAG = TAG;    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        if (getChildAt(0) != null) getChildAt(0).layout(l, t, r, b);    }    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-dispatchTouchEvent");        }        return super.dispatchTouchEvent(ev);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onInterceptTouchEvent");        }        return super.onInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        if (event.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onTouchEvent");        }        return super.onTouchEvent(event);    }}

再来就是Activity的代码了,如下:

import android.app.Activity;import android.os.Bundle;import android.support.annotation.Nullable;import android.view.ViewGroup;import com.example.viewpagertransformer.View.EventView;import com.example.viewpagertransformer.View.EventViewGroup;/** * @author: xiewenliang * @Filename: * @Description: * @date: 2017/4/14 14:17 */public class EventActivity extends Activity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);        EventViewGroup eventViewGroupA = new EventViewGroup(this, "A");        EventViewGroup eventViewGroupB = new EventViewGroup(this, "B");        EventViewGroup eventViewGroupC = new EventViewGroup(this, "C");        eventViewGroupA.setLayoutParams(lp);        eventViewGroupB.setLayoutParams(lp);        eventViewGroupC.setLayoutParams(lp);        eventViewGroupB.addView(eventViewGroupC);        eventViewGroupA.addView(eventViewGroupB);        setContentView(eventViewGroupA);    }}


Activity中我们的布局是三个容器嵌套在一起, 也就是A包涵B,B包涵C,A在容器的最低层,C在容器的最顶层,我们看一下打印的结果:

04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 16:45:24.793 9105-9105/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent04-14 16:45:24.794 9105-9105/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent04-14 16:45:24.794 9105-9105/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent


大家看到 事件的传递过程 就是从:A层dispatchTouchEvent -> A层onInterceptTouchEvent -> ~~ -> C层dispatchTouchEvent -> C层onInterceptTouchEvent ->

C层onTouchEvent -> ~ -> A层onTouchEvent。

从这里可以分析到 事件是从最底层的dispatchTouchEvent、onInterceptTouchEvent一直到最顶层的dispatchTouchEvent、onInterceptTouchEvent, 然后从最顶层的onTouchEvent回传到最底层的onTouchEvent。


明白了这些后,大家有看到,其实每个事件函数,都会返回一个布尔值,他们返回的布尔值是否会对事件传递产生影响呢? 下面我们通过事件来证明:

首先我们让A容器在dispatchTouchEvent方法中返回true,EventViewGroup的代码更改如下:

    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-dispatchTouchEvent");        }        if ("A".equals(TAG)) return true;        return super.dispatchTouchEvent(ev);    }

也就是说 当事件传递到A的dispatchTouchEvent方法中,我们返回true,来看看事件传递打印结果:

04-14 16:56:36.706 16544-16544/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent


我们发现 事件只打印了一条,根据前面我们得到的事件传递顺序,可以得出,如果在dispatchTouchEvent中返回true,事件会在该容器的dispatchTouchEvent中直接消耗,不会传递到该容器的onInterceptTouchEvent方法,也不会继续向下传递,为了证实我们的猜测,我们把它改成在B容器中的dispatchTouchEvent方法中返回true,猜测结果应该是:A层dispatchTouchEvent -> A层onInterceptTouchEvent -> B层dispatchTouchEvent, 事件通过A的两个方法传递到B层就会结束,EventViewGroup代码修改如下:

    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-dispatchTouchEvent");        }        if ("B".equals(TAG)) return true;        return super.dispatchTouchEvent(ev);    }

再来看看打印结果:

04-14 17:06:00.743 17930-17930/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:06:00.743 17930-17930/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:06:00.743 17930-17930/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent


结果也是证实了我们的猜测。得出的结论就是:如果在容器的dispatchTouchEvent中返回true,事件就会在该容器的dispatchTouchEvent方法中消耗,不会传递给该容器的其它事件处理方法,也不会继续向下传递事件。


接下来我们看看如果dispatchTouchEvent中返回false会是什么样的结果呢,EventViewGroup代码修改如下:

    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-dispatchTouchEvent");        }        if ("A".equals(TAG)) return false;        return super.dispatchTouchEvent(ev);    }

这里我们更改A容器执行到dispatchTouchEvent方法直接返回false,看下事件打印结果:

04-14 17:12:09.040 23155-23155/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent


我们看到,打印结果跟返回true是一样的,难道这个方法返回false和true是一样的吗,带着这个猜测,我们继续在B容器中该方法返回false,EventViewGroup代码修改如下:

    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-dispatchTouchEvent");        }        if ("B".equals(TAG)) return false;        return super.dispatchTouchEvent(ev);    }


打印结果:

04-14 17:15:30.366 26175-26175/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:15:30.366 26175-26175/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:15:30.366 26175-26175/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:15:30.366 26175-26175/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent


我们看到,dispatchTouchEvent方法返回true和返回false还是不一样的,返回true的时候,直接事件直接就在该方法内结束了,不会再传递给其它事件处理方法和容器,如果返回false,则不会继续调用该容器的其它事件处理方法,但是事件会提前传递到上层容器的onTouchEvent事件处理方法中。好了,dispatchTouchEvent事件处理机制我们就实验到这里。


下面来实验一下onInterceptTouchEvent方法中的返回值对事件传递有什么影响呢,我们先修改容器A中该方法的返回值为true,EventViewGroup代码修改如下:

    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onInterceptTouchEvent");        }        if ("A".equals(TAG)) return true;        return super.onInterceptTouchEvent(ev);    }


打印结果:

04-14 17:24:35.009 1720-1720/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:24:35.010 1720-1720/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:24:35.010 1720-1720/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent


我们看到 事件在容器A中就结束了,按照正常流程,事件传递到A的onInterceptTouchEvent方法,接下来就是B的dispatchTouchEvent方法了,但是这里没有把事件传递到B的dispatchTouchEvent中,而是直接就传递到了A的onTouchEvent方法中,由此,我们猜测,如果在容器的onInterceptTouchEvent方法中返回true,该事件不会继续想子容器或者子控件传递,而是提现就交给了本容器的onTouchEvent方法处理,如果是这样,我们猜测,如果在B容器的onInterceptTouchEvent方法中返回true,事件的传递顺序应该是这样的 A层dispatchTouchEvent -> A层onInterceptTouchEvent -> B层dispatchTouchEvent -> B层onInterceptTouchEvent ->

B层onTouchEvent -> A层onTouchEvent,  而不会传递到C层,为了验证猜测,EventViewGroup代码修改如下:

    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onInterceptTouchEvent");        }        if ("B".equals(TAG)) return true;        return super.onInterceptTouchEvent(ev);    }

打印结果:

04-14 17:30:42.210 7308-7308/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:30:42.210 7308-7308/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:30:42.210 7308-7308/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:30:42.210 7308-7308/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:30:42.211 7308-7308/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent04-14 17:30:42.211 7308-7308/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent


打印结果证明我们的猜测结果是正确的,所以总结如下:

当在容器的onInterceptTouchEvent方法中返回true,事件不会继续向子容器传递,而是提前传递给本容器的onTouchEvent方法。


下面我们来看看onInterceptTouchEvent方法中返回false,会是什么样的流程呢,我们先更改A容器的onInterceptTouchEvent方法返回false, EventViewGroup代码修改如下:

    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onInterceptTouchEvent");        }        if ("A".equals(TAG)) return false;        return super.onInterceptTouchEvent(ev);    }


打印结果:

04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent04-14 17:34:15.351 10383-10383/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent

我们发现,打印结果跟默认流程是一致的,是否onInterceptTouchEvent方法中默认返回值就是false呢,我们继续修改B中该方法返回值,EventViewGroup代码修改如下:

    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onInterceptTouchEvent");        }        if ("B".equals(TAG)) return false;        return super.onInterceptTouchEvent(ev);    }


打印结果:

04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent04-14 17:36:11.767 12071-12071/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent


打印结果证明我们的猜测是对的。如果容器的onInterceptTouchEvent方法中返回false,不会影响事件继续向下传递。


接下来我们分析最后一个方法,onTouchEvent,还是一样,先更改A容器中onTouchEvent返回true,EventViewGroup代码修改如下:

    @Override    public boolean onTouchEvent(MotionEvent event) {        if (event.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onTouchEvent");        }        if ("A".equals(TAG)) return true;        return super.onTouchEvent(event);    }

打印结果:

04-14 17:38:53.838 14427-14427/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:38:53.838 14427-14427/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:38:53.838 14427-14427/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:38:53.838 14427-14427/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:38:53.839 14427-14427/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 17:38:53.839 14427-14427/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 17:38:53.839 14427-14427/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent04-14 17:38:53.839 14427-14427/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent04-14 17:38:53.839 14427-14427/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent


我们看到打印流程跟正常流程一样,这是什么原因呢,我们看A容器的onTouchEvent本来就是事件传递的最后一个,所以看不出来影响,我们就更改B容器的onTouchEvent方法返回值为true,EventViewGroup代码修改如下:

    @Override    public boolean onTouchEvent(MotionEvent event) {        if (event.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onTouchEvent");        }        if ("B".equals(TAG)) return true;        return super.onTouchEvent(event);    }
打印结果:

04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent04-14 17:40:39.423 15966-15966/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent


我们看到 ,事件传递到B的onTouchEvent方法就结束了,我们猜测, 如果onTouchEvent返回true,事件就在onTouchEvent方法中消耗了,不会继续向上传递,为了验证猜测,我们继续修改C容器的onTouchEvent方法返回true, EventViewGroup代码修改如下:

    @Override    public boolean onTouchEvent(MotionEvent event) {        if (event.getAction() == MotionEvent.ACTION_DOWN) {            Log.i("MotionEvent", TAG + "-onTouchEvent");        }        if ("C".equals(TAG)) return true;        return super.onTouchEvent(event);    }


打印结果:

04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 17:43:26.432 18377-18377/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent


打印结果证实了我们的猜测,如果容器onTouchEvent返回true,事件就在onTouchEvent方法中消耗了,不会继续向上传递。

为了节省验证时间,我们直接修改C容器的onTouchEvent返回false, 看看结果,EventViewGroup代码修改如下:

04-14 17:45:05.666 19822-19822/com.example.viewpagertransformer I/MotionEvent: A-dispatchTouchEvent04-14 17:45:05.666 19822-19822/com.example.viewpagertransformer I/MotionEvent: A-onInterceptTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: B-dispatchTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: B-onInterceptTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: C-dispatchTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: C-onInterceptTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: C-onTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: B-onTouchEvent04-14 17:45:05.667 19822-19822/com.example.viewpagertransformer I/MotionEvent: A-onTouchEvent

由打印结果,我们发现 onTouchEvent的返回值是false, 不会拦截事件,事件会继续向上层容器的onTouchEvent传递。

由上述实例,我们可以综合下得出事件传播流程图如下:


好了 现在我们再来看看View类和ViewGroup类有什么区别呢,我们看到,其实ViewGroup就是多了一个onInterceptTouchEvent函数,该函数的作用,就是在返回true的时候事件不再向下传递,而是传递给容器本身的onTouchEvent函数,如果是返回false,则是继续传递给下一个容器或者控件,分析一下,我们可以看出,View这类不作为容器的控件,是没有子控件的,所以它通过dispatchTouchEvent调用父类的dispatchTouchEvent方法,其实就直接调用了onTouchEvent方法,流程图可以稍作修改如下:

好了  android事件分发的流程就总结到这里。


在实际的应用中,其实我们还有一个更便捷的方法来控制事件的传播,那就是getParent().requestDisallowInterceptTouchEvent(true/false); 具体用法代码如下:

private float oldx, oldy;    @Override    public boolean dispatchTouchEvent(MotionEvent event) {        // 通知该容器的所有上层容器,不要拦截或者消耗事件        getParent().requestDisallowInterceptTouchEvent(true);        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:            case MotionEvent.ACTION_MOVE:                float x = event.getX();                float y = event.getY();                if (Math.abs(x - oldx) > Math.abs(y - oldy)) {                    // 当检测到是横向滑动事件时,通知该容器的所有上层容器,不要拦截或者消耗事件,事件由该容器本身处理                    getParent().requestDisallowInterceptTouchEvent(true);                } else {                    // 当检测到是竖向滑动事件,通知该容器所有上层容器,该容器不再接收本次事件序列的剩余事件,由上层容器处理                    getParent().requestDisallowInterceptTouchEvent(false);                }                oldx = x;                oldy = y;                break;            case MotionEvent.ACTION_UP:            case MotionEvent.ACTION_CANCEL:                getParent().requestDisallowInterceptTouchEvent(false);                break;        }        return super.dispatchTouchEvent(event);    }

android事件分发流程就介绍到这里。




0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 吃了没熟的土豆怎么办 吃土豆没熟中毒怎么办 吃小土豆能中毒怎么办 猪吃土豆中毒了怎么办 吃了不熟的土豆怎么办 吃了变绿的土豆怎么办 吃炸洋芋中毒了怎么办 脸上长毒气痘痘怎么办 吃鸡游戏中遇到毒气怎么办 吃多了颠茄片怎么办 玲珑骰子沾了水怎么办 花的枝干长歪了怎么办 电脑中毒了怎么办开不了机 台湾竹长得太高怎么办 文竹长得太高怎么办 桑叶牡l丹长虫怎么办 日本海棠开完花后枯萎了怎么办 长寿冠海棠烂根怎么办 夏季长寿冠海棠掉叶怎么办 竹节海棠有点烂根怎么办? 丽格海棠烂茎怎么办 长寿花徒长不开花怎么办 长寿花植株长了怎么办 丽格海棠不爱长怎么办 竹节海棠太高了怎么办 绿萝叶子发黄烂根怎么办 发财树叶子发黄烂根怎么办 君子兰烂根叶子发黄怎么办 四季海棠花叶子干了怎么办 海棠花叶子枯萎枝干发黑怎么办 长寿花叶尖焦了怎么办 新买的盆栽蔫了怎么办 熬中药水太多了怎么办 秋根海棠烂根怎么办 大叶海棠烂根怎么办 玻璃海棠长得很高怎么办 玫瑰海棠叶子干焦怎么办 海棠树树干生虫怎么办 天竺葵花骨朵有虫子了怎么办? 被刺梅的刺扎了怎么办 被刺梅的刺划手了怎么办