View's onDraw() stops being called after four touch events


Last Updated:

  1. AlexSCH

    AlexSCH New Member This Topic's Starter

    Joined:
    Jul 19, 2010
    Messages:
    1
    Likes Received:
    0
    Hi everybody!
    I'am new to Android development and got stuck with one interesting issue.
    I've started implementing my own tree-like view, which will expand/collapse its nodes as user taps on them. Every node in a tree is a custom TextView(just for now) and there is two included ViewGroups to hold those textviews together. ViewGroup forced me to override it's onLayoutMethod() which in my case will call layout method on each TextView node. Also used drawChild(Canvas canvas, View child, long drawingTime) to pass drawing from viewgroup to it's children. Every node(textview) implements View.OnTouchListener to handle touch events and calls parent's requestLayout() method to force re-layout of tree nodes. Everything seems to be working fine, but unfortunately for not so long )) Problem is that drawChild() method get's invoked by system only four times!:( Every next (on touch event) requestLayout() call executes onLayout() as always but drawChild() never gets invoked again, only app restart helps.
    Application seems to be running normally and no exceptions are thrown into the console.
    Can anyone help solving limited paints problem ? Will appreciate any comments or advices.

    Here are sorces:
    Node.java
    Code (Text):
    1.  
    2. package com.example;
    3.  
    4. import android.content.Context;
    5. import android.graphics.Canvas;
    6. import android.graphics.Color;
    7. import android.graphics.Paint;
    8. import android.view.MotionEvent;
    9. import android.view.View;
    10. import android.view.ViewParent;
    11. import android.widget.TextView;
    12.  
    13. import java.util.Vector;
    14.  
    15.  
    16. public class Node extends TextView implements View.OnTouchListener
    17. {
    18.     private Object data;
    19.     private Vector children;
    20.     private Node parentNode;
    21.  
    22.     private boolean isExpanded = true;
    23.  
    24.     public Node(Context context)
    25.     {
    26.         super(context);
    27.         setOnTouchListener(this);
    28.     }
    29.  
    30.     public Node(Context context, Object data)
    31.     {
    32.         this(context);
    33.         setData(data);
    34.         if (data instanceof String)
    35.             setText((String) data);
    36.     }
    37.  
    38.     public Vector<Node> getChildren()
    39.     {
    40.         if (this.children == null)
    41.         {
    42.             return new Vector();
    43.         }
    44.         return this.children;
    45.     }
    46.  
    47.     public void setChildren(Vector children)
    48.     {
    49.         if (children != null)
    50.         {
    51.             for (int i = 0; i < children.size(); i++)
    52.             {
    53.                 ((Node) children.elementAt(i)).setParent(this);
    54.             }
    55.         }
    56.         this.children = children;
    57.     }
    58.  
    59.     public int getNumberOfChildren()
    60.     {
    61.         if (children == null)
    62.         {
    63.             return 0;
    64.         }
    65.         return children.size();
    66.     }
    67.  
    68.     public void addChild(Node child)
    69.     {
    70.         if (children == null)
    71.         {
    72.             children = new Vector();
    73.         }
    74.         child.setParent(this);
    75.         children.addElement(child);
    76.     }
    77.  
    78.     public void insertChildAt(int index, Node child) throws IndexOutOfBoundsException
    79.     {
    80.         if (index == getNumberOfChildren())
    81.         {
    82.             // this is really an append
    83.             addChild(child);
    84.         }
    85.         else
    86.         {
    87.             child.setParent(this);
    88.             children.elementAt(index); //just to throw the exception, and stop here
    89.             children.insertElementAt(child, index);
    90.         }
    91.     }
    92.  
    93.     public void removeChildAt(int index) throws IndexOutOfBoundsException
    94.     {
    95.         children.removeElementAt(index);
    96.     }
    97.  
    98.     public Object getData()
    99.     {
    100.         return this.data;
    101.     }
    102.  
    103.     public void setData(Object data)
    104.     {
    105.         this.data = data;
    106.     }
    107.  
    108.     public boolean isExpanded()
    109.     {
    110.         return isExpanded;
    111.     }
    112.  
    113.     public void setExpanded(boolean expanded)
    114.     {
    115.         isExpanded = expanded;
    116.     }
    117.  
    118.     public void setParent(Node parentNode)
    119.     {
    120.         this.parentNode = parentNode;
    121.     }
    122.  
    123.     public Node getParentNode()
    124.     {
    125.         return parentNode;
    126.     }
    127.  
    128.     public boolean equals(Object obj)
    129.     {
    130.         if (obj instanceof Node)
    131.         {
    132.             Object objectData = ((Node) obj).data;
    133.             if (data != null)
    134.                 return data.equals(objectData);
    135.             else
    136.                 return objectData == null;
    137.         }
    138.         else
    139.             return false;
    140.     }
    141.  
    142.     public int hashCode()
    143.     {
    144.         if (data == null)
    145.             return 0;
    146.         else
    147.             return data.hashCode();
    148.     }
    149.  
    150.     @Override
    151.     public void onDraw(Canvas canvas)
    152.     {
    153.         System.out.println("in node onDraw");
    154.         Paint paint = new Paint();
    155.         paint.setColor(Color.WHITE);
    156.         canvas.drawText((String) getData(), getLeft() + 10, getBottom(), paint);
    157.         if (!getChildren().isEmpty())
    158.         {
    159.             canvas.drawLine(getLeft(), getTop() + ((getBottom() - getTop()) / 2) + 1, getLeft() + 8, getTop() + ((getBottom() - getTop()) / 2) + 1, paint);
    160.             if (!isExpanded)
    161.                 canvas.drawLine(getLeft() + 4, getTop() + 4, getLeft() + 4, getBottom(), paint);
    162.         }      
    163.     }
    164.  
    165.     public boolean onTouch(View view, MotionEvent motionEvent)
    166.     {
    167.         if (motionEvent.getAction() == MotionEvent.ACTION_DOWN)
    168.         {
    169.             isExpanded = !isExpanded;
    170.             System.out.println("Expanded=" + isExpanded);
    171.             ViewParent viewParent = view.getParent();
    172.             viewParent.requestLayout();
    173.             return true;
    174.         }
    175.         return false;
    176.     }
    177. }
    178.  
    SimpleTree.java which holds Nodes
    Code (Text):
    1.  
    2. package com.example;
    3.  
    4.  
    5. import android.content.Context;
    6. import android.graphics.Canvas;
    7. import android.view.ViewGroup;
    8.  
    9. import java.io.DataInputStream;
    10. import java.io.DataOutputStream;
    11. import java.io.IOException;
    12. import java.util.Vector;
    13.  
    14. public class SimpleTree extends ViewGroup
    15. {
    16.     private Node rootElement;
    17.    
    18.     public SimpleTree(Context context)
    19.     {
    20.         super(context);
    21.         rootElement = new Node(context, new Long(-1));
    22.     }
    23.  
    24.     public Node getRootElement()
    25.     {
    26.         return this.rootElement;
    27.     }
    28.  
    29.     public Vector toVector()
    30.     {
    31.         Vector list = new Vector();
    32.         walk(rootElement, list);
    33.         return list;
    34.     }
    35.  
    36.     public String toString()
    37.     {
    38.         return toVector().toString();
    39.     }
    40.  
    41.     private void walk(Node element, Vector list)
    42.     {
    43.         list.addElement(element);
    44.         Vector children = element.getChildren();
    45.         for (int i = 0; i < element.getNumberOfChildren(); i++)
    46.         {
    47.             walk((Node) children.elementAt(i), list);
    48.         }
    49.     }
    50.  
    51.     public Node findNode(Object data)
    52.     {
    53.         return findNode(rootElement, data);
    54.     }
    55.  
    56.     private Node findNode(Node node, Object data)
    57.     {
    58.         if (node.getData().equals(data))
    59.             return node;
    60.         else
    61.         {
    62.             Vector children = node.getChildren();
    63.             for (int i = 0; i < children.size(); i++)
    64.             {
    65.                 Node res = findNode((Node) children.elementAt(i), data);
    66.                 if (res != null)
    67.                     return res;
    68.             }
    69.  
    70.             return null;
    71.         }
    72.     }
    73.  
    74.     public void insertToTreeAsChild(Node parent, Node bufferTaskNode)
    75.     {
    76.         addView(bufferTaskNode);
    77.         Node parentNode = findNode(parent.getData());
    78.         if (parentNode == null)
    79.             parentNode = getRootElement();
    80.  
    81.         Node taskNode = findNode(bufferTaskNode.getData());
    82.         if (taskNode == null)
    83.             taskNode = bufferTaskNode;
    84.         if (parentNode.isExpanded())
    85.             parentNode.insertChildAt(0, taskNode);
    86.         else
    87.             parentNode.addChild(taskNode);
    88.     }
    89.  
    90.     public void insertToTreeAsSibling(Node parent, Node bufferTaskNode, Node focusTaskNode)
    91.     {
    92.         addView(bufferTaskNode);
    93.         Node parentNode;
    94.         Node taskNode = findNode(bufferTaskNode.getData());
    95.         if (taskNode == null)
    96.             taskNode = bufferTaskNode;
    97.         if (parent == null)
    98.             parentNode = getRootElement();
    99.         else
    100.         {
    101.             parentNode = findNode(parent.getData());
    102.  
    103.             if (parentNode == null)
    104.                 parentNode = getRootElement();
    105.         }
    106.  
    107.         taskNode.setParent(parentNode);
    108.         if (focusTaskNode != null)
    109.         {
    110.             for (int i = 0; i < parentNode.getNumberOfChildren(); i++)
    111.             {
    112.                 String tempChild = (String) ((Node) parentNode.getChildren().elementAt(i)).getData();
    113.                 if (tempChild.equals(((String) focusTaskNode.getData())))
    114.                 {
    115.                     parentNode.insertChildAt(i + 1, taskNode);
    116.                     break;
    117.                 }
    118.             }
    119.         }
    120.         else
    121.             parentNode.insertChildAt(0, taskNode);
    122.     }
    123.  
    124.     @Override
    125.     public void onDraw(Canvas canvas)
    126.     {
    127.         paintElements(canvas, getRootElement());
    128.     }
    129.  
    130.     private void paintElements(Canvas canvas, Node node)
    131.     {
    132.         if (!(node.getData() instanceof Long))
    133.         {
    134.             node.draw(canvas);
    135.         }
    136.         if (node.getChildren() != null && node.getChildren().size() != 0 && node.isExpanded())
    137.         {
    138.             for (int i = 0; i < node.getChildren().size(); i++)
    139.             {
    140.                 paintElements(canvas, node.getChildren().elementAt(i));
    141.             }
    142.         }
    143.     }
    144.  
    145.     @Override
    146.     protected void onLayout(boolean b, int left, int top, int right, int bottom)
    147.     {
    148.         layoutElements(getRootElement(), 0, 1);
    149.     }
    150.  
    151.     private int layoutElements(Node node, int left, int top)
    152.     {
    153.         if (!(node.getData() instanceof Long))
    154.         {
    155.             node.layout(left * 15, top * 15, 50 + left * 15, top * 15 + (int) node.getPaint().getTextSize());
    156.         }
    157.         if (node.getChildren() != null && node.getChildren().size() != 0 && node.isExpanded())
    158.         {
    159.             top++;
    160.             for (int i = 0; i < node.getChildren().size(); i++)
    161.             {
    162.                 top = layoutElements(node.getChildren().elementAt(i), left + 1, top + i);
    163.             }
    164.         }
    165.         return top;
    166.     }
    167.  
    168. }
    169.  
    General TreeView which operates SimpleTree
    Code (Text):
    1.  
    2. public class TreeView extends ViewGroup
    3. {
    4.     SimpleTree tree;
    5.  
    6.     public TreeView(Context context)
    7.     {
    8.         super(context);
    9.         tree = new SimpleTree(context);
    10.         addView(tree);
    11.         tree.insertToTreeAsSibling(tree.getRootElement(), new Node(context, "test1"), null);
    12.         tree.insertToTreeAsChild(tree.findNode("test1"), new Node(context, "test11"));
    13.         tree.insertToTreeAsChild(tree.findNode("test11"), new Node(context, "test111"));
    14.         tree.insertToTreeAsChild(tree.findNode("test11"), new Node(context, "test112"));
    15.         tree.insertToTreeAsSibling(tree.getRootElement(), new Node(context, "test2"), tree.findNode("test1"));
    16.     }
    17.  
    18.     @Override
    19.     protected void onLayout(boolean b, int i, int i1, int i2, int i3)
    20.     {
    21.         tree.onLayout(b, i, i1, i2, i3);        
    22.     }
    23.  
    24.     @Override
    25.     protected boolean drawChild(Canvas canvas, View child, long drawingTime)
    26.     {
    27.         tree.onDraw(canvas);
    28.         return true;
    29.     }
    30.  
    31.     @Override
    32.     public boolean onTouchEvent(MotionEvent event)
    33.     {
    34.         return tree.dispatchTouchEvent(event);  
    35.     }
    36. }
    37.  
    and finally Activity class
    Code (Text):
    1.  
    2. public class MLOActivity extends Activity
    3. {
    4.     public static final String GROUP_ID = "Group";
    5.     public static final String CHILD_ID = "Child";
    6.     public static final int GROUPS = 2;
    7.     public static final int CHILDREN = 2;
    8.  
    9.     /**
    10.      * Called when the activity is first created.
    11.      */
    12.     @Override
    13.     public void onCreate(Bundle savedInstanceState)
    14.     {
    15.         super.onCreate(savedInstanceState);      
    16.         TreeView view = new TreeView(this);
    17.         setContentView(view);
    18.         view.invalidate();        
    19.     }  
    20. }
    21.  
    Thanks in advance.
     

    Advertisement
  2. markb

    markb Well-Known Member

    Joined:
    Sep 14, 2009
    Messages:
    148
    Likes Received:
    26
    Hi AlexSCH

    If I get the chance I'll experiment with your code later. But for now, I can only make a suggestion.

    Are the calls to drawChild happening when the application starts, or in response to a touch event? I suspect that it's just happening when the application draws itself for the first time, and the touch events are not having any effect on the drawing.

    In your onTouch method you try to force a redraw by calling viewParent.requestLayout() - but maybe that isn't having the desired effect. Maybe you could try viewParent.invalidate() instead?

    I haven't played with ViewGroups and can't try anything out at the moment. So I could be talking rubbish. But it might be worth a try, if you haven't tried it already.

    Mark
     

Share This Page

Loading...