简体   繁体   English

ACTION_DOWN,ACTION_UP和onClick事件

[英]ACTION_DOWN, ACTION_UP and onClick event

I have a listview whose items are a custom views composed by 2 labels and a button in a relativelayout. 我有一个listview,其项目是由2个标签和一个相对布局中的按钮组成的自定义视图。

When doing this, the 'feedback' of the listview button clicking -the item changed background color while you touch it- dissapears so I decided to do it using ACTION_DOWN and ACTION_UP 执行此操作时,单击列表视图按钮的“反馈”-该项目在您触摸时更改了背景色-消失了,所以我决定使用ACTION_DOWN和ACTION_UP

I did this class to put in all listviews with the same issue: 我做了这个课程来放入所有具有相同问题的列表视图:

// The same instance of this class is setted as onTouchListener to the labels and the layout
public class OnTouchChangeColor implements OnTouchListener {

TransitionDrawable transition;
private final int duration = 250;
public static final int INITCOLOR = Color.WHITE;
public static final int FINALCOLOR = Color.CYAN;
// this will be the layout container of the labels and the button
ViewGroup layout = null;
public OnTouchChangeColor(ViewGroup layout){
    update(layout);
}

public void update(ViewGroup layout){
    this.layout = layout;
    TransitionDrawable t = new TransitionDrawable(new Drawable[]{new ColorDrawable(INITCOLOR), new ColorDrawable(FINALCOLOR)});
    layout.setBackgroundDrawable(t);
    transition = (TransitionDrawable) layout.getBackground();
}
@Override
public boolean onTouch(View v, MotionEvent event) {
    int eventaction = event.getAction();
    switch (eventaction) {
        case MotionEvent.ACTION_DOWN: 
        transition.startTransition(duration);
        break;
        case MotionEvent.ACTION_UP:   
        transition.reverseTransition(duration);
        break;
    }
    // tell the system that we handled the event but a further processing is required
    return false;
}

The problem is that the item gets the touch event ACTION_DOWN but not the ACTION_UP, thats: the background changes from white to cyan in 250ms, after of this it makes the onclick event, but it does not do the ACTION_UP... 问题在于,该项目获得了触摸事件ACTION_DOWN但没有获得ACTION_UP,那就是:背景在250毫秒内从白色变为青色,此后将产生onclick事件,但不会执行ACTION_UP ...

The onClick does this: onClick会执行以下操作:

@Override
public void onClick(View v) {
    try {
        loadData();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Intent intent = new Intent(context, ActDestiny.class);
    intent.putExtra("stop", true);
    context.startActivity(intent);
}

Well: it goes to the next activity but it doesn't put its background back to white... More than this: sometimes it doesn't go to its destiny but the background changes to cyan and is stuck in cyan... 好吧:它进入下一个活动,但它不会使背景变回白色...不仅如此:有时它并没有达到预定的目的,但是背景变成了青色,并停留在青色中...

I've read in android documentation that returning 'false' in the ontouch function: 我已经阅读了Android文档,该文档在ontouch函数中返回“ false”:

So, if you return false when the down action event is received, you indicate that you have not consumed the event and are also not interested in subsequent actions from this event. 因此,如果在收到按下动作事件时返回false,则表明您尚未消耗该事件,并且也对该事件的后续动作不感兴趣。 Thus, you will not be called for any other actions within the event, such as a finger gesture, or the eventual up action event. 因此, 不会在事件内要求您进行任何其他操作,例如手指手势或最终的上动作事件。

So if I return true the feedback works but the event is consumed and the onclick doesn't works... 因此,如果我返回true,则反馈有效,但事件已消耗且onclick不起作用...

So I don't know what to do to get the 'feedback' of touching a item and the onclick event working.... 所以我不知道该怎么做才能使触摸项目的“反馈”和onclick事件正常工作。

I could call the onClick inside the ACTION_UP but its very ugly -specially thinking in the 'onLongClick' event-. 我可以在ACTION_UP内调用onClick,但是它非常难看-特别是在“ onLongClick”事件中的思考-。

Its possible to use the ACTION_DOWN, ACTION_UP to make animations and onClick event to make the logic of the app at once? 是否可以使用ACTION_DOWN,ACTION_UP制作动画以及使用onClick事件立即制作应用逻辑?

How can I restore -and costumize- the feedback of 'pushing a button'? 如何恢复并汇总“按下按钮”的反馈?

EDIT TO POST CODE: 编辑邮编:

Well, there's requested code. 好吧,这里有要求的代码。

The xml: xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/layout_titular_mp3"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">

<TextView
    android:id="@+id/LblTitulo"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_toLeftOf="@id/btnAccion"
    android:textSize="20dp"
    android:textStyle="bold" />

<TextView
    android:id="@+id/LblSubTitulo"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/LblTitulo"
    android:layout_toLeftOf="@id/btnAccion"
    android:text=" "
    android:textSize="12dp"
    android:textStyle="normal" />

<Button
    android:id="@+id/btnAccion"
    android:layout_width="48dp"
    android:layout_height="wrap_content"
    android:layout_alignParentRight="true"
    android:background="@drawable/playbutton_style"
    android:gravity="center_vertical|center_horizontal|right"
    android:visibility="gone" />

</RelativeLayout>

And the adapter's code. 以及适配器的代码。 Note that when I do this: 请注意,当我这样做时:

cvh.updateCustomOnClickBases(titActual, context,posicion);
cvh.updateOnTouchListeners();    

I do it because the listView only creates the views that are on screen and when you scroll down it recicles the one that goes out (the upper one) whit the info of the next item in your array of data (that will be shown down, as the next one). 我这样做是因为listView仅创建屏幕上的视图,当您向下滚动它时,记录下来的(上面的)记录了数据数组中下一项的信息(将显示在屏幕上,作为下一个)。

So I recicle the eventlisteners too updating their references. 因此,我记录了事件侦听器也更新了它们的引用。 The code is below. 代码如下。

public class AdaptPlayList extends BaseAdapter {
private final Context context;
ArrayList<PlayList> datos;
long id;

public AdaptPlayList(Context context, ArrayList<PlayList> datos, int typ) {
    this.datos = datos;
    this.context = context;
}

public void updatePlaylist(ArrayList<PlayList> pl){
    ThreadPreconditions.checkOnMainThread();
    this.datos = pl;
    notifyDataSetChanged();
}

@Override
public int getCount(){
     return datos.size();
}

@Override
public PlayList getItem(int index) {
    return datos.get(index);
}

@Override
public long getItemId(int index) {
    return index;
}


public View getView(int posicion, View convertView, ViewGroup parent) {
    final PlayList titActual = getItem(posicion); 
    CancionViewHolder cvh;
    if (convertView == null) {
        cvh = new CancionViewHolder();
        convertView = LayoutInflater.from(context).inflate(R.layout.titularmp3, parent, false);
        OnPlaylistItemClick itemClick = new OnPlaylistItemClick(titActual, context,posicion);
        cvh.titulo = (TextView) convertView.findViewById(R.id.LblTitulo);
        cvh.btnAction = (Button) convertView.findViewById(R.id.btnAccion);
        cvh.layout = (ViewGroup)convertView.findViewById(R.id.layout_titular_mp3);
        cvh.click = itemClick;
        cvh.longClick = itemClick;
        cvh.btnClick = new OnPlaylistButtonClick(titActual, context,posicion);
        convertView.setTag(cvh);
    }else{
        cvh = (CancionViewHolder)convertView.getTag();
    }
    cvh.updateCustomOnClickBases(titActual, context,posicion);
    cvh.updateOnTouchListeners();
    TextView titulo = cvh.titulo;
    Button btnAction = cvh.btnAction;
    titulo.setText(titActual.getDesc());
    btnAction.setVisibility(View.VISIBLE);
    btnAction.setOnClickListener(cvh.btnClick);
    titulo.setOnClickListener(cvh.click);
    titulo.setOnLongClickListener(cvh.longClick);
    return convertView;

}
}

class OnPlaylistItemClick  extends CustomOnClickBase implements OnClickListener, OnLongClickListener{

public OnPlaylistItemClick(PlayList pl, Context ctx, int position) {
    super(pl, ctx, position);
}

@Override
public boolean onLongClick(View v) {
    // do things....
            //
    Intent intent = new Intent(context, ActListadoCancionesAsync.class);
    intent.putExtra("stopMusic", true);
    context.startActivity(intent);
    return true;
}

@Override
public void onClick(View v) {
    // do more things!
    }
}

}

class OnPlaylistButtonClick  extends CustomOnClickBase implements OnClickListener{
PlayList titActual;

public OnPlaylistButtonClick(PlayList pl, Context ctx, int position) {
    super(pl, ctx, position);
    titActual = pl;
}

@Override
public void onClick(View v) {
    // do things
            //....
    Intent intent = new Intent(context, ActListadoCancionesAsync.class);
    intent.putExtra("stopMusic", true);
    context.startActivity(intent);
}
}

With this holder and clickbase I avoid object creations (I build a event listeners of the listview's items that are updated instead of create new listeners) 有了这个持有人和clickbase,我避免了对象的创建(我创建了一个被更新的listview项的事件监听器,而不是创建新的监听器)

public class CancionViewHolder{
    public TextView titulo;
    public TextView subtitulo;
    public ToggleButton button;
    public Button btnAction;
    public OnClickListener btnClick;
    public OnClickListener click;
    public OnLongClickListener longClick;
    public ViewGroup layout = null;

    /**Actualiza los eventos que estan cacheados para que apunten a sus nuevos contenidos del adapter. De otro modo, como los
     * datos del adapter se moveran mientras que los views seran reutilizados los eventos apuntarian a la anterior posicion
     * @param datosItem
     * @param ctx
     * @param pos
     */
    public void updateCustomOnClickBases(Object datosItem, Context ctx, int pos){
        ((CustomOnClickBase)click).updateObject(datosItem, ctx,pos, layout);
        ((CustomOnClickBase)longClick).updateObject(datosItem, ctx,pos, layout);
        ((CustomOnClickBase)btnClick).updateObject(datosItem, ctx,pos, layout);
    }

    /**
     * Establece los listeners que hacen efectos cuando se pulsa algo
     */
    public void updateOnTouchListeners() {
        if (layout != null) {
            OnTouchChangeColor cc = new OnTouchChangeColor(layout);
            layout.setOnTouchListener(cc);
            if (subtitulo != null){
                subtitulo.setOnTouchListener(cc);
            }
            if (titulo != null){
                titulo.setOnTouchListener(cc);
            }
        }
    }
}

And

public abstract class CustomOnClickBase {
protected Object datosItem;
protected Context context;
protected int position;
protected ViewGroup layout;

public CustomOnClickBase(Object datosItem, Context ctx, int position){
    updateObject(datosItem, ctx, position, layout);
}

public void updateObject(Object datosItem, Context ctx, int position, ViewGroup layout){
    this.datosItem = datosItem;
    context =ctx;
    this.position = position;
    this.layout = layout;
}
}

I think you need to change your onTouch() method 我认为您需要更改onTouch()方法

@Override
public boolean onTouch(View v, MotionEvent event) {
    int eventaction = event.getAction();
    switch (eventaction) {
        case MotionEvent.ACTION_DOWN: 
        transition.startTransition(duration);
        //Tell Android that you can handle this MotionEvent, and you 
        //want to keep informed of further events of this touch
        return true;
        break;
        case MotionEvent.ACTION_UP:   
        transition.reverseTransition(duration);
        break;
    }
    // tell the system that we handled the event but a further processing is required
    return false;
}

Hope it helps. 希望能帮助到你。

public boolean onTouch(MotionEvent ev) {
 ...
 return super.onTouch(ev);
}

Maybe you should not return false by yourself. 也许您不应该自己返回false。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM