Android OnClickListener funktioniert auf LinearLayout nicht

derSoerrn

Aktives Mitglied
Guten Tag,

ich habe ein merkwürdiges Problem: Es gibt eine CustomView Klasse
Code:
extends LinearLayout
. Diese Klasse lädt ein XML-File mit zwei TextViews. Nun wollte ich, dass man auf meine CustomView-Klasse klicken kann, also setzte ich einen onClickListener. Dieser funktioniert allerdings nicht auf API Level 10 (Android 2.3.3), ab API-Level 16 jedoch schon. Kann mir jemand von Euch helfen?

Anbei die beiden Klassen, um die es geht:

Java:
package de.projektkurs.viewpager;

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class Drag extends LinearLayout implements DragSource, DropTarget{
	
	private Context c;
	@SuppressWarnings("unused")
	private AttributeSet as;
	@SuppressWarnings("unused")
	private int style;
	
	private String sTyp;
	private int apiLevel = android.os.Build.VERSION.SDK_INT;
	
	public long ID;
	
	private int iTyp;
	private int iRaum;
	private int iIndex;
	
	public boolean mEmpty;
	
	private TextView tvTyp, tvName;
	private View v;
	public ViewGroup vg;
	
	public Drag(Context context) {
		super(context);
		c = context;
		ladeObjekte();
	}
	
	public Drag(Context context, AttributeSet attrs) {
		super(context);
		c = context;
		as = attrs;
		ladeObjekte();
	}
	
	public Drag(Context context, AttributeSet attrs, int style) {
		super(context);
		c = context;
		as = attrs;
		this.style = style;
		ladeObjekte();
	}
	
	/**
	 * Es werden die TextViews des Objekts initalisiert
	 */
	private void ladeObjekte(){
		v = new View(c);
        LayoutInflater inflater = LayoutInflater.from(c);
        v = inflater.inflate(R.layout.gfx_objekte, null, false);
        this.addView(v);
		tvTyp = (TextView)v.findViewById(R.id.tvObjektTyp);
		tvName = (TextView)v.findViewById(R.id.tvObjektName);		
	}
	
	/**
	 * Legt die erste Textzeile des View-Objekts fest.
	 * @param raum
	 */
	@SuppressWarnings("deprecation")
	public void setzeRaum(int raum){
		switch (raum) {
		case Werte.M:
			if (apiLevel <= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1){
		    	v.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.matrix_object_selector));
		    } else{
		    	v.setBackground(c.getResources().getDrawable(R.drawable.matrix_object_selector));
		    }
			break;
		case Werte.R2:
			if (apiLevel <= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1){
		    	v.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.r2_object_selector));
		    } else{
		    	v.setBackground(c.getResources().getDrawable(R.drawable.r2_object_selector));
		    }
			break;
		case Werte.R3:
			if (apiLevel <= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1){
		    	v.setBackgroundDrawable(c.getResources().getDrawable(R.drawable.r3_object_selector));
		    } else{
		    	v.setBackground(c.getResources().getDrawable(R.drawable.r3_object_selector));
		    }
			break;
			
		default:
			break;
		}
	}
	
	/**
	 * Legt den Typ des Objekts fest.
	 * @param typ
	 */
	public void setzeTyp(int typ){
		switch (typ) {
		case Werte.TYP_M:
			sTyp = "Matrix";
			break;
		case Werte.TYP_P2D:
			sTyp = "Punkt";
			break;
		case Werte.TYP_V2D:
			sTyp = "Vektor";
			break;
		case Werte.TYP_G2D:
			sTyp = "Gerade";
			break;
		case Werte.TYP_P3D:
			sTyp = "Punkt";
			break;
		case Werte.TYP_V3D:
			sTyp = "Vektor";
			break;
		case Werte.TYP_G3D:
			sTyp = "Gerade";
			break;
		case Werte.TYP_E3D:
			sTyp = "Ebene";
			break;
		default:
			sTyp = "Falscher Typ...";
			break;
		}
		tvTyp.setText(sTyp);
	}
	
	/**
	 * Legt den Namen des Objekts fest.
	 * @param name
	 */
	public void setzeName(String name){
		tvName.setText(name);
	}
	
	public void setzeID(long id){
		this.ID = id;
	}

	@Override
	public void getHitRect(Rect outRect) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void getLocationOnScreen(int[] loc) {
		// TODO Auto-generated method stub
		
	}
	
	//Für Drag'n'Drop Opperation benötigt:
	
	/**
	 * This method is called to determine if the DragSource has something to
	 * drag.
	 * 
	 * @return True if there is something to drag
	 */

	public boolean allowDrag() {
		// There is something to drag if the cell is not empty.
		return !mEmpty;
	}

	/**
	 * setDragController
	 * 
	 */

	public void setDragController(DragController dragger) {
		// Do nothing. We do not need to know the controller object.
	}

	/**
	 * onDropCompleted
	 * 
	 */

	public void onDropCompleted(View target, boolean success) {
		// If the drop succeeds, the image has moved elsewhere.
		// So clear the image cell.
		System.out.println(success+" = Success");
		if (success) {
			mEmpty = true;
			if (this.getId() >= 0) {
				int bg = mEmpty ? R.color.cell_empty : R.color.cell_filled;
				setBackgroundResource(bg);
				setBackgroundColor(color.transparent);
				Toast.makeText(c, "Hallo", Toast.LENGTH_SHORT).show();
			} else {
				// For convenience, we use a free-standing ImageCell to
				// take the image added when the Add Image button is clicked.
				Toast.makeText(c, "Hallo", Toast.LENGTH_SHORT).show();
			}
		}else{
			Toast.makeText(c, "Wuhuuuu es funktioniert :)))", Toast.LENGTH_SHORT).show();
		}
	}

	/**
 */
	// DropTarget interface implementation

	/**
	 * Handle an object being dropped on the DropTarget. This is the where the
	 * drawable of the dragged view gets copied into the ImageCell.
	 * 
	 * @param source
	 *            DragSource where the drag started
	 * @param x
	 *            X coordinate of the drop location
	 * @param y
	 *            Y coordinate of the drop location
	 * @param xOffset
	 *            Horizontal offset with the object being dragged where the
	 *            original touch happened
	 * @param yOffset
	 *            Vertical offset with the object being dragged where the
	 *            original touch happened
	 * @param dragView
	 *            The DragView that's being dragged around on screen.
	 * @param dragInfo
	 *            Data associated with the object being dragged
	 * 
	 */
	@SuppressLint("NewApi")
	@SuppressWarnings("deprecation")
	public void onDrop(DragSource source, int x, int y, int xOffset,
			int yOffset, DragView dragView, Object dragInfo) {
		// Mark the cell so it is no longer empty.
		mEmpty = false;
		int bg = mEmpty ? R.color.cell_empty : R.color.cell_filled;
		setBackgroundResource(bg);

		// The view being dragged does not actually change its parent and switch
		// over to the ImageCell.
		// What we do is copy the drawable from the source view.
		LinearLayout sourceView = (LinearLayout) source;
		Drawable d = sourceView.getBackground();
		if (d != null) {
			if(apiLevel < android.os.Build.VERSION_CODES.JELLY_BEAN){
				this.setBackgroundDrawable(d);
			}else{
				this.setBackground(d);
			}
		}

		// toast ("onDrop cell " + mCellNumber);

	}

	/**
	 * React to a dragged object entering the area of this DropSpot. Provide the
	 * user with some visual feedback.
	 */
	public void onDragEnter(DragSource source, int x, int y, int xOffset,
			int yOffset, DragView dragView, Object dragInfo) {
		int bg = mEmpty ? R.color.cell_empty_hover : R.color.cell_filled_hover;
		setBackgroundResource(bg);
	}

	/**
	 * React to something being dragged over the drop target.
	 */
	public void onDragOver(DragSource source, int x, int y, int xOffset,
			int yOffset, DragView dragView, Object dragInfo) {
	}

	/**
	 * React to a drag
	 */
	public void onDragExit(DragSource source, int x, int y, int xOffset,
			int yOffset, DragView dragView, Object dragInfo) {
		int bg = mEmpty ? R.color.cell_empty : R.color.cell_filled;
		setBackgroundResource(bg);
	}

	/**
	 * Check if a drop action can occur at, or near, the requested location.
	 * This may be called repeatedly during a drag, so any calls should return
	 * quickly.
	 * 
	 * @param source
	 *            DragSource where the drag started
	 * @param x
	 *            X coordinate of the drop location
	 * @param y
	 *            Y coordinate of the drop location
	 * @param xOffset
	 *            Horizontal offset with the object being dragged where the
	 *            original touch happened
	 * @param yOffset
	 *            Vertical offset with the object being dragged where the
	 *            original touch happened
	 * @param dragView
	 *            The DragView that's being dragged around on screen.
	 * @param dragInfo
	 *            Data associated with the object being dragged
	 * @return True if the drop will be accepted, false otherwise.
	 */
	public boolean acceptDrop(DragSource source, int x, int y, int xOffset,
			int yOffset, DragView dragView, Object dragInfo) {
		// An ImageCell accepts a drop if it is empty and if it is part of a
		// grid.
		// A free-standing ImageCell does not accept drops.
		return mEmpty && (this.getId() >= 0);
	}

	/**
	 * Estimate the surface area where this object would land if dropped at the
	 * given location.
	 * 
	 * @param source
	 *            DragSource where the drag started
	 * @param x
	 *            X coordinate of the drop location
	 * @param y
	 *            Y coordinate of the drop location
	 * @param xOffset
	 *            Horizontal offset with the object being dragged where the
	 *            original touch happened
	 * @param yOffset
	 *            Vertical offset with the object being dragged where the
	 *            original touch happened
	 * @param dragView
	 *            The DragView that's being dragged around on screen.
	 * @param dragInfo
	 *            Data associated with the object being dragged
	 * @param recycle
	 *            {@link Rect} object to be possibly recycled.
	 * @return Estimated area that would be occupied if object was dropped at
	 *         the given location. Should return null if no estimate is found,
	 *         or if this target doesn't provide estimations.
	 */
	public Rect estimateDropLocation(DragSource source, int x, int y,
			int xOffset, int yOffset, DragView dragView, Object dragInfo,
			Rect recycle) {
		return null;
	}

	/**
 */
	// Other Methods

	/**
	 * Return true if this cell is empty. If it is, it means that it will accept
	 * dropped views. It also means that there is nothing to drag.
	 * 
	 * @return boolean
	 */

	public boolean isEmpty() {
		return mEmpty;
	}

	/**
	 * Call this view's onClick listener. Return true if it was called. Clicks
	 * are ignored if the cell is empty.
	 * 
	 * @return boolean
	 */

	public boolean performClick() {
		if (!mEmpty)
			return super.performClick();
		return false;
	}

	/**
	 * Call this view's onLongClick listener. Return true if it was called.
	 * Clicks are ignored if the cell is empty.
	 * 
	 * @return boolean
	 */

	public boolean performLongClick() {
		if (!mEmpty)
			return super.performLongClick();
		return false;
	}
	
	

}

und

Java:
package de.projektkurs.viewpager;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import de.projektkurs.elementActivity1.ElementActivity1;
import de.projektkurs.tools.ObjectContainer;
import de.projektkurs.tools.Werte;

@SuppressLint("NewApi")
public class R2Adapter extends BaseAdapter implements OnLongClickListener{
	private Context c;
	private OnLongClickListener listener;
	
	private String sName;
	private int iTyp, iRaum;
	
	public R2Adapter(Context context){
		c = context;
	}
		
	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return ObjectContainer.math2d.size();
	}

	@Override
	public Object getItem(int position) {
		// TODO Auto-generated method stub
		return ObjectContainer.math2d.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(final int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		sName = ObjectContainer.math2d.get(position).gibName();
		iRaum = Werte.R2;
		iTyp = ObjectContainer.math2d.get(position).gibTyp();
		Drag d = null;
	    if (convertView == null) {
	        // Wenn noch kein DragObjekt existiert wird eins erstellt, 
	    	// sonst wird es geändert.
	        d = new Drag(c);
	        d.setLayoutParams(new GridView.LayoutParams(170, 140));
	        d.setzeName(sName);
	        d.setzeTyp(iTyp);
	        d.setzeRaum(iRaum);
	        d.setzeID(position);
	        System.out.println(sName+", "+iTyp+", "+iRaum);
	    } else {
	        d = (Drag) convertView;
	    }

	    d.setzeID(position);
	    d.vg = (GridView) parent;
	    
	    d.setClickable(true);
	    
	    d.setOnLongClickListener (listener);
	    
	    d.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				System.out.println("Wurde Geklickt");
			    Intent i = new Intent().setClass(c, ElementActivity1.class);
                i.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                
                Bundle b = new Bundle();
                b.putInt("room", Werte.R2);
                b.putInt("type", ObjectContainer.math2d.get(position).gibTyp());
                b.putInt("index0", position);
                b.putInt("count", 1);
                
                i.putExtras(b);

                // Activity starten
                c.startActivity(i);
			}
			
		});
	    
		return d;
	}

	@Override
	public boolean onLongClick(View v) {
		// TODO Auto-generated method stub
		return false;
	}
	
	/**
	 * Es wird ein LongClickListener gesetzt.
	 * @param l {@link OnLongClickListener}
	 */
	public void setzeLongClickListener(OnLongClickListener l){
		listener = l;
	}
}

BTW, der LongClickListener funktioniert ebenfalls nicht :/


Gruß
 
Ziemlich viel Text...

Grundsätzlich funktionieren die OnClickListener auf LinearLayout auch unter API 10

Kannst Du mal abgespeckten Code liefern mit dem man das Phänomen nachvollziehen kann?
 
Die CustomView Klasse (hat jetzt nur noch Methoden, um z.B. den Namen zu setzen)
Java:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public class Objekt extends LinearLayout {

	private Context c;
	private AttributeSet as;
	private int style;

	private String sTyp;
	private int apiLevel = android.os.Build.VERSION.SDK_INT;

	public long ID;

	private int iTyp;
	private int iRaum;
	private int iIndex;

	public boolean mEmpty;

	private TextView tvTyp, tvName;
	private View v;
	public ViewGroup vg;

	public Objekt(Context context) {
		super(context);
		c = context;
		ladeObjekte();
	}

	public Objekt(Context context, AttributeSet attrs) {
		super(context);
		c = context;
		as = attrs;
		ladeObjekte();
	}

	public Objekt(Context context, AttributeSet attrs, int style) {
		super(context);
		c = context;
		as = attrs;
		this.style = style;
		ladeObjekte();
	}

	/**
	 * Es werden die TextViews des Objekts initalisiert
	 */
	private void ladeObjekte() {
		v = new View(c);
		LayoutInflater inflater = LayoutInflater.from(c);
		v = inflater.inflate(R.layout.gfx_objekte, null, false);
		this.addView(v);
		tvTyp = (TextView) v.findViewById(R.id.tvObjektTyp);
		tvName = (TextView) v.findViewById(R.id.tvObjektName);
	}

	/**
	 * Legt die erste Textzeile des View-Objekts fest.
	 * 
	 * @param raum
	 */
	public void setzeRaum(int raum) {

		if (apiLevel <= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
			v.setBackgroundDrawable(c.getResources().getDrawable(
					R.drawable.ic_launcher));
		} else {
			v.setBackground(c.getResources()
					.getDrawable(R.drawable.ic_launcher));
		}
		System.out.println(apiLevel);
		System.out
				.println(android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1);
	}

	/**
	 * Legt den Typ des Objekts fest.
	 * 
	 * @param typ
	 */
	public void setzeTyp(int typ) {
		// Abgespeckt, nur da, damit etwas im Feld stehen würde
		tvTyp.setText("Typ");
	}

	/**
	 * Legt den Namen des Objekts fest.
	 * 
	 * @param name
	 */
	public void setzeName(String name) {
		tvName.setText(name);
	}
	
	/**
	 * 
	 * @param id
	 */
	public void setzeID(long id) {
		this.ID = id;
	}

}

Die Adapter Klasse, welche die CustomView Objekte verwaltet

Java:
public class R2Adapter extends BaseAdapter implements OnLongClickListener{
	private Context c;
	private OnLongClickListener listener;
	
	private String sName;
	private int iTyp, iRaum;
	
	public R2Adapter(Context context){
		c = context;
	}
		
	@Override
	public int getCount() {
		// Gibt die Anzahl der Objekte wieder
		return ObjectContainer.math2d.size();
	}

	@Override
	public Object getItem(int position) {
		// Gibt das Objekte an der angegeben Stelle zurück
		return ObjectContainer.math2d.get(position);
	}

	@Override
	public long getItemId(int position) {
		// TODO Auto-generated method stub
		return position;
	}

	@Override
	public View getView(final int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub
		Drag d = null;
	    if (convertView == null) {
	        // Wenn noch kein DragObjekt existiert wird eins erstellt, 
	    	// sonst wird es geändert.
	        d = new Drag(c);
	        d.setLayoutParams(new GridView.LayoutParams(170, 140));
	    } else {
	        d = (Drag) convertView;
	    }

	    d.vg = (GridView) parent;
	    
	    d.setClickable(true);
	    
	    d.setOnLongClickListener (listener);
	    
	    d.setOnClickListener(new OnClickListener(){

			@Override
			public void onClick(View v) {
				System.out.println("Wurde Geklickt");
			}
		});
	    
		return d;
	}

	@Override
	public boolean onLongClick(View v) {
		// TODO Auto-generated method stub
		return false;
	}
	
	/**
	 * Es wird ein LongClickListener gesetzt.
	 * @param l {@link OnLongClickListener}
	 */
	public void setzeLongClickListener(OnLongClickListener l){
		listener = l;
	}
}

Vielleicht noch zur Erklärung: Es gibt ein Fragment, auf diesem liegt ein ViewPager mit 3 Seiten. Der R2Adapter (2. Klasse) füllt den Viewpager mit Objekten aus einer Liste.

Soll ich noch mehr Klassen hochladen bzw noch weiter "abspecken"?
 
Ich würde sagen, da frisst ein Adapter am Weg von Activity über FragmentHost zu Fragment den Event. Häng überall mal einen Listener an der den Namen der verwendeten Komponente ausspuckt und schau was passiert.

Liest sich vielleicht stümperhaft aber was besseres fällt mir da jetzt nicht ein.
 
Das verstehe ich leider nicht so ganz. Was soll ich denn für einen Listener benutzen und auf welche Komponenten soll ich diesen dann adden?
 
Kurze Verständnisfrage: Warum setzt du für jedes Listen-Objekt einen ClickListener anstatt dass du einen onItemClickListener für die ganze Liste setzt?
 
Weil ich blöd war 😀 ich habe es jetzt selbst so geschrieben, wie Du meintest. Mich würde aber trd interessieren, warum man mit API lvl. 16 auf die Objekte klicken konnte, mit 10 jedoch nicht. Weißt Du das?
 

Zurück
Oben