Проблемы с прокруткой в ​​LinearLayout - PullRequest
1 голос
/ 06 декабря 2010

У меня довольно простой вопрос, который я почему-то не могу понять. Я использую FrameLayout с собственным представлением (onDrawn переопределяется) и другим прозрачным представлением, расширяющим LinearLayout. Я хочу добавить прокрутку для прозрачного представления, но если я использую ScrollView в XML, возникает исключение Classcast.

Моя альтернатива заключалась в том, чтобы реализовать прокрутку самостоятельно (например, с помощью scrollTo в LinearLayout, где я не могу найти никакого примера, использующего этот метод), но OnGestureListener не запускает onScroll, тогда как onShowPress и onLongPress запускаются. Затем я попытался использовать onTouchEvent в LinearLayout, но он распознает только ACTION_DOWN, а не ACTION_MOVE. На мой взгляд, все это прекрасно работает.

Здесь 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>

Вот основная конструкция 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;
}
}

Вот основная конструкция 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");
}

}

А вот конструкция 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 Ответ

1 голос
/ 11 декабря 2010

Ладно, думаю, я наконец все понял:

  1. ClassCastException было выброшено, потому что в моей TransparentPanel я пытаюсь назначить LayoutParams на панель, не указывая какой тип LayoutParams. Я думал, что это должен быть LinearLayout.LayoutParams, но на самом деле мне нужно назначить LayoutParams ViewGroup, в который я помещаю View, т.е. RelativeLayout в моем случае.

  2. Моя GlassPanel размещается лучше в нижней части FrameLayout, а не сверху. MotionEvents затем передаются сверху вниз, как и ожидалось. Я просто начинаю с того, что лежит сверху, и если событие не обрабатывается этим слоем, я возвращаю false и передаю событие следующему слою, вместо того, чтобы иметь реальную стеклянную панель сверху.

  3. Чтобы обработать событие в GlassPane поверх FrameLayout, мне просто нужно переопределить метод onTouchEvent во всех представлениях, которые используют GlassPane в качестве EventListener. Так же, как в WaterfallView в приведенном выше коде. Но осторожные MotionEvent.getX () и MotionEvent.getY () возвращают значения, относящиеся к этому представлению, а не абсолютные. Решение (2) прекрасно работает относительно GlassPane.

...