1

I have a fairly simple question which somehow I can't figure out. I'm using a FrameLayout with an own view (onDrawn is overriden) and another transparent view which extends LinearLayout. I want to add scrolling for the transparent view, but if I use ScrollView in the XML a Classcast exception is thrown.

My alternative was to implement scrolling on my own (e.g. with scrollTo in LinearLayout, where I can't find any example using that method), but the OnGestureListener doesn't trigger onScroll, while onShowPress and onLongPress are triggered. I then tried to use onTouchEvent in the LinearLayout, but it only recognises ACTION_DOWN, not ACTION_MOVE. In my own view all that works perfectly.

Here the XML:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/home_container" android:layout_width="fill_parent" android:layout_height="fill_parent"> <com.unimelb.pt2.ui.WaterfallView android:id="@+id/waterfall_view" android:layout_width="fill_parent" android:layout_height="fill_parent" android:apiKey="0DUEIIn35xtmfWC2DXprK5kqNF-aEaNgRJ4ONxw"/> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:gravity="bottom" android:paddingLeft="0px" android:paddingTop="0px" android:paddingRight="0px"> <com.unimelb.pt2.ui.TransparentPanel android:id="@+id/workbench" android:layout_width="fill_parent" android:layout_height="10px" android:paddingTop="0px" android:paddingLeft="0px" android:paddingBottom="0px" android:paddingRight="0px"> </com.unimelb.pt2.ui.TransparentPanel> </LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" android:gravity="right" android:paddingLeft="0px" android:paddingTop="0px" android:paddingRight="0px"> <com.unimelb.pt2.ui.TransparentPanel android:id="@+id/tagarea" android:layout_width="50px" android:layout_height="fill_parent" android:paddingTop="0px" android:paddingLeft="0px" android:paddingBottom="0px" android:paddingRight="0px"> </com.unimelb.pt2.ui.TransparentPanel> </LinearLayout> </FrameLayout> 

Here the basic construct of the WaterfallView:

public class WaterfallView extends View { private GestureDetector gestureScanner; private Vector<PictureEntry> allPictures = new Vector<PictureEntry>(); public WaterfallView(Context context) { super(context); this.initialize(context); } public void initialize(Context context) { this.setFocusable(true); this.setClickable(true); this.context = context; allPictures.add(new PictureEntry(context, R.drawable.sample_0)); allPictures.add(new PictureEntry(context, R.drawable.sample_1)); allPictures.add(new PictureEntry(context, R.drawable.sample_2)); allPictures.add(new PictureEntry(context, R.drawable.sample_3)); allPictures.add(new PictureEntry(context, R.drawable.sample_4)); allPictures.add(new PictureEntry(context, R.drawable.sample_5)); allPictures.add(new PictureEntry(context, R.drawable.sample_6)); allPictures.add(new PictureEntry(context, R.drawable.sample_7)); } public void setGestureDetector(GlassPane gp) { gestureScanner = new GestureDetector(context, gp); } @Override protected void onDraw(Canvas canvas) { Iterator<PictureEntry> iter = allPictures.iterator(); int i = 0; while (iter.hasNext()) { PictureEntry pic = iter.next(); pic.draw(canvas) } invalidate(); } @Override public boolean onTouchEvent(MotionEvent event) { if (gestureScanner.onTouchEvent(event)) { return Prototype.glass.pictureTouch(event); } else return false; } } 

Here the basic construct of the GlassPane:

public class GlassPane implements OnGestureListener { public GlassPane(WaterfallView waterfall) { super(); waterfall.setGestureDetector(this); } public boolean pictureTouch(MotionEvent event) { // Handles drag and drop and zoom pinch } public boolean onDown(MotionEvent e) { Log.i("Test", "DOWN"); return false; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.i("Test", "FLING"); return false; } @Override public void onLongPress(MotionEvent e) { Log.i("Test", "LONG PRESS"); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.i("Test", "SCROLL"); return true; } @Override public void onShowPress(MotionEvent e) { Log.i("Test", "SHOW PRESS"); } } 

And here the construct of the TransparentPanel:

public class TransparentPanel extends LinearLayout { private Paint innerPaint, borderPaint; private int width, height, scrollOffset; private Context mContext; public TransparentPanel(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; init(); } public TransparentPanel(Context context) { super(context); init(); } private void init() { innerPaint = new Paint(); innerPaint.setARGB(225, 75, 75, 75); // gray innerPaint.setAntiAlias(true); } public void setDimension(int w, int h) { width = w; height = h; this.setLayoutParams(new LayoutParams(width, height)); this.invalidate(); } @Override protected void dispatchDraw(Canvas canvas) { RectF drawRect = new RectF(); drawRect.set(0, 0, width, height); canvas.drawRect(drawRect, innerPaint); super.dispatchDraw(canvas); } private void measure() { if(this.getOrientation()==LinearLayout.VERTICAL) { int h = 0; for(int i=0; i<this.getChildCount(); i++) { View v = this.getChildAt(i); h += v.getMeasuredHeight(); } height = (h < height) ? height : h; Log.d(Prototype.TAG, "mW:"+width+", mH:"+height); } this.setMeasuredDimension(width, height); } } 

1 Answer 1

1

Okay, I think I finally figured everything out:

  1. The ClassCastException was thrown because in my TransparentPanel I try to assign LayoutParams to the panel without stating which kind of LayoutParams. I thought it should be LinearLayout.LayoutParams but in fact I need to assign the LayoutParams of the ViewGroup in which I place the View, i.e. RelativeLayout in my case.

  2. My GlassPanel is placed better on the bottom of the FrameLayout rather than on the top. The MotionEvents are than passed down from top to bottom as expected. I just start with whatever is lying on top and if the event is not handled by that layer I return false and pass down the event to the next layer rather than having a real GlassPane on top.

  3. In order to handle the event in the GlassPane on top of the FrameLayout I just need to override the onTouchEvent method in all the Views that use the GlassPane as EventListener. Just like in WaterfallView in the above code. But careful MotionEvent.getX() and MotionEvent.getY() return values relative to that View and not absolute. Solution (2) works perfect relatively to the GlassPane.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.