2010-12-06 8 views
1

J'ai une question assez simple que je n'arrive pas à comprendre. J'utilise un FrameLayout avec une vue propre (onDrawn est redéfini) et une autre vue transparente qui étend LinearLayout. Je veux ajouter un défilement pour la vue transparente, mais si j'utilise ScrollView dans le XML, une exception Classcast est levée. Mon alternative était d'implémenter le défilement par moi-même (par exemple avec scrollTo dans LinearLayout, où je ne trouve aucun exemple utilisant cette méthode), mais OnGestureListener ne déclenche pas onScroll, tandis que onShowPress et onLongPress sont déclenchés. J'ai alors essayé d'utiliser onTouchEvent dans le LinearLayout, mais il reconnaît seulement ACTION_DOWN, pas ACTION_MOVE. À mon avis, tout cela fonctionne parfaitement.Problèmes de défilement dans LinearLayout

Voici le 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> 

Ici, la construction de base du 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; 
} 
} 

Ici, la construction de base du 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"); 
} 

} 

Et ici la construction de le 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); 
} 

} 

Répondre

1

D'accord, je pense que je tout finalement compris:

  1. Le ClassCastException a été jeté parce que dans mon TransparentPanel je tente d'assigner LayoutParams au panneau sans indiquer quel type de LayoutParams. Je pensais que ce devrait être LinearLayout.LayoutParams mais en fait je dois assigner les LayoutParams du ViewGroup dans lequel je place la View, c'est-à-dire RelativeLayout dans mon cas. Mon GlassPanel est mieux placé sur le fond du FrameLayout plutôt que sur le dessus. Les MotionEvents sont transmis de haut en bas comme prévu. Je commence simplement par ce qui se trouve sur le dessus et si l'événement n'est pas géré par cette couche, je retourne false et passe l'événement à la couche suivante plutôt que d'avoir un vrai GlassPane en haut. Pour gérer l'événement dans le GlassPane au-dessus du FrameLayout, j'ai juste besoin de surcharger la méthode onTouchEvent dans toutes les vues qui utilisent le GlassPane comme EventListener. Tout comme dans WaterfallView dans le code ci-dessus. Mais attention MotionEvent.getX() et MotionEvent.getY() retournent des valeurs relatives à cette vue et non absolues. La solution (2) fonctionne parfaitement par rapport au GlassPane.

Questions connexes