Problems with Scrolling in LinearLayout

笑着哭i 提交于 2019-12-08 05:34:29

问题


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:


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.



来源:https://stackoverflow.com/questions/4362213/problems-with-scrolling-in-linearlayout

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!