android - LinearLayout 中的滚动问题

标签 android scrollview gestures

我有一个相当简单的问题,不知何故我无法弄清楚。我正在使用一个带有自己 View (onDrawn 被覆盖)的 FrameLayout 和另一个扩展 LinearLayout 的透明 View 。我想为透明 View 添加滚动,但如果我在 XML 中使用 ScrollView,则会抛出 Classcast 异常。

我的替代方案是自己实现滚动(例如,在 LinearLayout 中使用 scrollTo,我找不到任何使用该方法的示例),但 OnGestureListener 不会触发 onScroll,而 onShowPress 和 onLongPress 会被触发。然后我尝试在 LinearLayout 中使用 onTouchEvent,但它只能识别 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. ClassCastException 被抛出是因为在我的 TransparentPanel 中我尝试将 LayoutParams 分配给面板而不说明哪种 LayoutParams。我认为它应该是 LinearLayout.LayoutParams 但实际上我需要分配我放置 View 的 ViewGroup 的 LayoutParams,即在我的例子中是 RelativeLayout。

  2. 我的 GlassPanel 最好放在 FrameLayout 的底部而不是顶部。 MotionEvents 然后按预期从上到下传递。我只是从位于顶部的任何内容开始,如果事件未由该层处理,我将返回 false 并将事件传递到下一层,而不是在顶部放置一个真正的 GlassPane。

  3. 为了处理 FrameLayout 顶部的 GlassPane 中的事件,我只需要覆盖所有使用 GlassPane 作为 EventListener 的 View 中的 onTouchEvent 方法。就像上面代码中的 WaterfallView 一样。但要小心 MotionEvent.getX() 和 MotionEvent.getY() 返回相对于该 View 的值,而不是绝对值。解决方案 (2) 相对于 GlassPane 而言效果完美。

关于android - LinearLayout 中的滚动问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4362213/

相关文章:

ios - 如果我添加 GestureRecognizer,MapView 将不再工作

android - onScale 事件后触发奇怪的 onScroll 事件

android - 带有嵌入式浏览器的 Google OAuth 2.0 和强制门户

java - 有人可以解释为什么我不能向这个 ScrollView 添加额外的按钮吗?

java - 如何设置 GridPane 自动调整以适应 JavaFX 中的内容

android - 试图刷掉 native FlatList 中的项目但没有收到 onResponderTerminationRequest 事件

java - MPAndroid 图表 - 图表未更新

java - 在模拟器上执行我的 Android 应用程序时出现异常。 (但在手机上运行正常)

android - Fused Location Api 从 GPS 获取时间

android - 如何在软键盘上方设置布局