2015-12-19 1 views
3

J'essaie de créer une vue personnalisée, d'hériter du groupe de vues et de mettre en page des sous-vues personnalisées dans ce groupe de vues de manière personnalisée. Fondamentalement, j'essaye de créer une vue de calendrier semblable à celle dans les perspectives, où chaque événement prend la taille d'écran par rapport à sa longueur. J'initialise une ArrayList de View dans le constructeur du ViewGroup, redéfinit onMeasure, onLayout et onDraw, et tout fonctionne bien, sauf que ... les vues rendues commencent à (0,0), même si je mets leur gauche et bonnes propriétés à d'autres valeurs. Leur largeur et hauteur sortent ok, seulement leur haut et à gauche sont faux.Android: les vues personnalisées sont dessinées à des coordonnées x, y incorrectes

Ce code, que j'abrégé pour plus de clarté et de simplicité:

public class CalendarDayViewGroup extends ViewGroup { 
    private Context mContext; 
    private int mScreenWidth = 0; 

    private ArrayList<Event> mEvents; 
    private ArrayList<View> mEventViews; 

    // CalendarGridPainter is a class that draws the background grid. 
    // this one works fine so I didn't write its actual code here. 
    // it just takes a Canvas and draws lines on it. 
    // I also tried commenting out this class and got the same result, 
    // so this is DEFINITELY not the problem. 
    private CalendarGridPainter mCalendarGridPainter; 

    public CalendarDayViewGroup(Context context, Date date) { 
     super(context); 
     init(date, context); 
    } 

    //... other viewGroup constructors go here... 

    private void init(Date date, Context context) { 
     mContext = context; 
     // the following line loads events from a database 
     mEvents = AppointmentsRepository.getByDateRange(date, date); 

     // inflate all event views 
     mEventViews = new ArrayList<>(); 
     LayoutInflater inflater = LayoutInflater.from(mContext); 
     for (int i = 0; i < mEvents.size(); i++) { 
      View view = getSingleEventView(mEvents.get(i), inflater); 
      mEventViews.add(view); 
     } 

     // set this flag so that the onDraw event is called 
     this.setWillNotDraw(false); 
    } 

    private View getSingleEventView(Event event, LayoutInflater inflater) { 
     View view = inflater.inflate(R.layout.single_event_view, null); 
     // [set some properties in the view's sub-views] 
     return view; 
    } 

    @Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.getSize(heightMeasureSpec)); 

     // get screen width and create a new GridPainter if needed 
     int screenWidth = MeasureSpec.getSize(widthMeasureSpec); 
     if (mScreenWidth != screenWidth) 
     { 
      mScreenWidth = screenWidth; 
      mCalendarGridPainter = new CalendarGridPainter(screenWidth); 
     } 

     int numChildren = mEvents.size(); 
     for (int i = 0; i < numChildren; i++) { 
      View child = mEventViews.get(i); 
      Event event = mEvents.get(i); 

      // event width is the same as screen width 
      int specWidth = MeasureSpec.makeMeasureSpec(mScreenWidth, MeasureSpec.EXACTLY); 

      // event height is calculated by its length, the calculation was ommited here for simplicity 
      int eventHeight = 350; // actual calculation goes here... 
      int specHeight = MeasureSpec.makeMeasureSpec(eventHeight, MeasureSpec.EXACTLY); 
      child.measure(specWidth, specHeight); 
     } 
    } 


    @Override 
    protected void onLayout(boolean changed, int l, int t, int r, int b) { 
     int numChildren = mEvents.size(); 
     for (int i = 0; i < numChildren; i++) { 
      View child = mEventViews.get(i); 
      Event event = mEvents.get(i); 

      int eventLeft = 0; 
      int eventTop = (i + 1) * 200; // test code, make each event start 200 pixels after the previous one 
      int eventWidth = eventLeft + child.getMeasuredWidth(); 
      int eventHeight = eventTop + child.getMeasuredHeight(); 
      child.layout(eventLeft, eventTop, eventWidth, eventHeight); 
     } 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     // draw background grid 
     mCalendarGridPainter.paint(canvas); 
     // draw events 
     for (View view : mEventViews) { 
      view.draw(canvas); 
     } 
     super.onDraw(canvas); 
    } 
} 
+0

Avez-vous connecté les valeurs qui définissent la largeur? –

+0

J'ai débogué et suivi tous les habitants. Les valeurs sont définies correctement. En outre, la largeur n'est pas le problème - largeur et hauteur sont définies correctement. La valeur supérieure est le problème: bien qu'il soit défini sur 200, 400, 600 etc., toutes les vues sont affichées à 0. – user884248

Répondre

1

Pour une raison quelconque, il semble que les enfants de manière sont dessinés avec ViewGroup s est que le ViewGroup se traduit par la toile à la position de l'enfant alors attire l'enfant à 0,0.

Mais il s'avère que ViewGroup s'occupera de tout le dessin d'enfants pour vous. Je pense que si vous simplifiez votre méthode onDraw() vous devriez être tous ensemble:

@Override 
protected void onDraw(Canvas canvas) { 
    // draw background grid 
    mCalendarGridPainter.paint(canvas); 
    // draw events 
    super.onDraw(canvas); 
} 

Maintenant que je regarde votre code plus loin, je remarque que vous gonflez votre point de vue de l'enfant dans le code de votre ViewGroup. Il est préférable de faire tout cela en dehors de votre ViewGroup, d'ajouter ces vues en utilisant addView(), puis d'utiliser getChildCount() et getChildAt() pour accéder aux vues enfants pendant onLayout().

+0

Je suppose que je devrais remplacer getView() et getViewCount() pour que cela fonctionne? – user884248

+0

Je ne pense pas. Essayez le override 'onDraw()' que j'ai posté, essayez aussi de ne pas surcharger 'onDraw()' du tout, juste pour voir le comportement par défaut. –

+0

Oh, attendez une seconde, n'avez-vous pas appelé 'CalendarDayViewGroup.addView()' sur vos vues d'événements? Mise à jour de ma réponse ... –