1

(Workaround) Solution can be found at te end of my question

I've been searching for hours but I couldn't find anything that solves my problem.

I have a custom View which bassicaly draws a line from one point to another. That view is than added to the rootview.

MainActivity.java

package be.serafijnboelaert.lapse.activity;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.GridLayout;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.Toast;

import be.serafijnboelaert.lapse.R;


public class MainActivity extends Activity {

    private RelativeLayout rl;
    private GridLayout glActionMenu;
    private int width;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rl = (RelativeLayout) this.findViewById(R.id.mainContent);

        rl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                rl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                setWidth(rl.getMeasuredWidth());
            }
        });


    }

    private void setWidth(int width) {
        this.width = width;


        glActionMenu = (GridLayout) this.findViewById(R.id.glActionMenu);


        for(int i = 0 ; i < glActionMenu.getChildCount() ;i++) {
            GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
            lp.width = width / 5;
            lp.height = lp.width;

            if((i >= 5 && i < 10) || (i >= 15 && i< 20)) {
                lp.height = lp.width / 2 + lp.width / 4;
            }
            glActionMenu.getChildAt(i).setLayoutParams(lp);
        }
        MyCustomView myCustomView;

        glActionMenu.getChildAt(glActionMenu.getChildCount() -1).addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                Toast.makeText(v.getContext(), "hello",Toast.LENGTH_LONG).show();

                ImageButton ib1 = (ImageButton) findViewById(R.id.ibOpenPictureActivity);

                ib1.setBackgroundColor(Color.RED);
                ImageButton ib2 = (ImageButton) findViewById(R.id.ibOpenAlbumActivity);
                ib2.setBackgroundColor(Color.GREEN);

                glActionMenu.setBackgroundColor(Color.BLUE);

                float fromX = ib1.getLeft() +ib1.getWidth() + rl.getLeft();
                float fromY = ib1.getTop() + ib1.getHeight()/2 + glActionMenu.getTop();
                float toX =  ib2.getLeft();
                float toY = ib2.getTop() + ib2.getHeight()/2;

                MyCustomView customView = new MyCustomView(v.getContext(), fromX, fromY, toX,toY);
                rl.addView(customView);
            }
        });
    }
}

MyCustomView.java

    package be.serafijnboelaert.lapse.activity;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by Samsung on 25/12/2014.
 */
public class MyCustomView extends View {

    private float fromX;
    private float fromY;
    private float toX;
    private float toY;

    public MyCustomView(Context context, float fromX, float fromY, float toX, float toY) {
        super(context);
        this.fromX = fromX;
        this.fromY = fromY;
        this.toX = toX;
        this.toY = toY;
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyCustomView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Paint paint = new Paint();
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10);
        canvas.drawLine(fromX,fromY,toX,toY, paint);
    }

    @Override
    public void onMeasure(int wms, int hms){
        setMeasuredDimension(MeasureSpec.getSize(wms), MeasureSpec.getSize(hms));
    }
}

activity_main.xml

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    tools:context=".MainActivity"
    android:id="@+id/mainContent">


    <include
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        layout="@layout/action_menu"
        android:layout_gravity="center"
        android:layout_centerInParent="true" />
</RelativeLayout>

action_menu.xml

<?xml version="1.0" encoding="utf-8"?>



<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" android:layout_height="wrap_content"
    android:columnCount="5"
    android:rowCount="5"
    android:columnOrderPreserved="false"
    android:rowOrderPreserved="true"
    android:id="@+id/glActionMenu" >

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="0"
        android:layout_row="0" />

    <ImageButton
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:id="@+id/ibOpenPictureActivity"
        android:scaleType="fitXY"
        android:background="@android:color/transparent"
        android:src="@drawable/ic_picture"
        android:layout_column="1"
        android:layout_row="0"/>

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="2"
        android:layout_row="0" />

    <ImageButton
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:id="@+id/ibOpenAlbumActivity"
        android:background="@android:color/transparent"
        android:scaleType="fitXY"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/ic_album"
        android:layout_column="3"
        android:layout_row="0" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="4"
        android:layout_row="0" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="0"
        android:layout_row="1" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="1"
        android:layout_row="1" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="2"
        android:layout_row="1" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="3"
        android:layout_row="1" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="4"
        android:layout_row="1" />

    <ImageButton
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:id="@+id/ibOpenLapseActivity"
        android:scaleType="fitXY"
        android:layout_gravity="center_horizontal"
        android:background="@android:color/transparent"
        android:src="@drawable/ic_lapse"
        android:layout_column="0"
        android:layout_row="2" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="1"
        android:layout_row="2" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="2"
        android:layout_row="2" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="3"
        android:layout_row="2" />

    <ImageButton
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:id="@+id/ibOpenSettingsActivity"
        android:background="@android:color/transparent"
        android:scaleType="fitXY"
        android:layout_gravity="center_horizontal"
        android:src="@drawable/ic_settings"
        android:layout_column="4"
        android:layout_row="2" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="0"
        android:layout_row="3" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="1"
        android:layout_row="3" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="2"
        android:layout_row="3" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="3"
        android:layout_row="3" />
    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="4"
        android:layout_row="3" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="0"
        android:layout_row="4" />

    <ImageButton
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:id="@+id/btnOpenShareActivity"
        android:scaleType="fitXY"
        android:background="@android:color/transparent"
        android:src="@drawable/ic_share"
        android:layout_column="1"
        android:layout_row="4" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="2"
        android:layout_row="4" />

    <ImageButton
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:id="@+id/ibOpenHelpActivity"
        android:scaleType="fitXY"
        android:layout_gravity="center_horizontal"
        android:background="@android:color/transparent"
        android:src="@drawable/ic_help"
        android:layout_column="3"
        android:layout_row="4" />

    <View
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:layout_column="4"
        android:layout_row="4" />


</GridLayout>

The problem is, that the onDraw method from my customview is never called, but the other layout changes (buttons in green and red and gridlayout in blue) works fine..

I need that line to be drawad AFTER the layoutchanges from the actionbuttons, because the line simply connects two action buttons with eachother.

I know, I set an GlobalLayoutChangeListerer on every button, it's pretty useless but thats for testing purposes.

I really hope I can find the solution here.

Thnx in advance!

(Workaround) Solution

package be.serafijnboelaert.lapse.activity;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.GridLayout;
import android.widget.ImageButton;
import android.widget.RelativeLayout;

import be.serafijnboelaert.lapse.R;


public class MainActivity extends Activity {

    private RelativeLayout rl;
    private GridLayout glActionMenu;
    private int width;

    private float fromX;
    private float fromY;
    private float toX;
    private float toY;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        rl = (RelativeLayout) this.findViewById(R.id.mainContent);

        rl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                rl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                setWidth(rl.getMeasuredWidth());
            }
        });


    }

    private void setWidth(int width) {
        this.width = width;


        glActionMenu = (GridLayout) this.findViewById(R.id.glActionMenu);


        for(int i = 0 ; i < glActionMenu.getChildCount() ;i++) {
            GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
            lp.width = width / 5;
            lp.height = lp.width;

            if((i >= 5 && i < 10) || (i >= 15 && i< 20)) {
                lp.height = lp.width / 2 + lp.width / 4;
            }
            glActionMenu.getChildAt(i).setLayoutParams(lp);
        }

        glActionMenu.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                ImageButton ib1 = (ImageButton) findViewById(R.id.ibOpenPictureActivity);
                ImageButton ib2 = (ImageButton) findViewById(R.id.ibOpenAlbumActivity);

                fromX = ib1.getRight() + rl.getLeft();
                fromY = ib1.getTop() + ib1.getHeight()/2 + glActionMenu.getTop();
                toX =  ib2.getLeft();
                toY = ib2.getTop() + ib2.getHeight()/2 + glActionMenu.getTop();
            }
        });

        glActionMenu.postDelayed(new Runnable()
        {
            @Override
            public void run()
            {
                MyCustomView customView = new MyCustomView(MainActivity.this, fromX, fromY, toX, toY);
                rl.addView(customView);
            }
        }, 10);
    }
}
Serafijn
  • 87
  • 7
  • try calling setWillNotDraw (false) in MyCustomView constructor – ata Dec 25 '14 at 02:32
  • Can you place some log statements in MyCustomView's constructor and onDraw method to confirm if they are being called? – Athena Dec 25 '14 at 02:41
  • glActionMenu.postDelayed(new Runnable() { @Override public void run() { customView = new MyCustomView(MainActivity.this, fromX, fromY, toX, toY); rl.addView(customView); } }, 10); –  Dec 25 '14 at 05:55
  • The constructor is called but the onDraw method not. I've placed some breackpoints for testing this. – Serafijn Dec 25 '14 at 08:24

2 Answers2

1

As this answer said : onDraw() is called each time the view needs to be drawn. When the view is off screen then onDraw() is never called.

are you sure your Views were truly visible? by the way, attempt to set a viable background to that Views to determinate whether they show or not.

MyCustomView customView = new MyCustomView(...);
// set the background to green
customView.setBackgroundColor(0x0000FF00);
rl.addView(customView);
Community
  • 1
  • 1
VinceStyling
  • 3,707
  • 3
  • 29
  • 44
0

Try this code working for me.

public class MainActivity extends ActionBarActivity
{
    private RelativeLayout rl;
    private GridLayout glActionMenu;
    private int width;
    private MyCustomView customView;
    private int fromX;
    private int fromY;
    private int toX;
    private int toY;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        // MyCustomView customView = new MyCustomView(this, 0, 0, 100,200);
        // setContentView(customView);

        setContentView(R.layout.activity_main);
        rl = (RelativeLayout) this.findViewById(R.id.mainContent);

        // RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(500, 500);
        // customView = new MyCustomView(MainActivity.this, 0, 0, 100, 200);
        // customView.setBackgroundColor(Color.DKGRAY);
        // rl.addView(customView);

        rl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener()
        {
            @SuppressLint("NewApi")
            @Override
            public void onGlobalLayout()
            {
                rl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                setWidth(rl.getMeasuredWidth());
            }
        });
        // setWidth(rl.getMeasuredWidth());
    }

    private void setWidth(int width)
    {
        this.width = width;

        glActionMenu = (GridLayout) this.findViewById(R.id.glActionMenu);

        for (int i = 0; i < glActionMenu.getChildCount(); i++)
        {
            GridLayout.LayoutParams lp = new GridLayout.LayoutParams();
            lp.width = width / 5;
            lp.height = lp.width;

            if ((i >= 5 && i < 10) || (i >= 15 && i < 20))
            {
                lp.height = lp.width / 2 + lp.width / 4;
            }
            glActionMenu.getChildAt(i).setLayoutParams(lp);
        }

        glActionMenu.getChildAt(glActionMenu.getChildCount() - 1).addOnLayoutChangeListener(new View.OnLayoutChangeListener()
        {

            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
            {
                Toast.makeText(v.getContext(), "hello", Toast.LENGTH_LONG).show();

                ImageButton ib1 = (ImageButton) findViewById(R.id.ibOpenPictureActivity);

                ib1.setBackgroundColor(Color.RED);
                ImageButton ib2 = (ImageButton) findViewById(R.id.ibOpenAlbumActivity);
                ib2.setBackgroundColor(Color.GREEN);

                glActionMenu.setBackgroundColor(Color.WHITE);

                fromX = ib1.getLeft() + ib1.getWidth() + rl.getLeft();
                fromY = ib1.getTop() + ib1.getHeight() / 2 + glActionMenu.getTop();
                toX = ib2.getLeft();
                toY = ib2.getTop() + ib2.getHeight() / 2;

                // customView = new MyCustomView(MainActivity.this, 0, 0, 100, 200);
                // customView.setBackgroundColor(Color.DKGRAY);
                // rl.addView(customView);
                // customView.invalidate();
            }

        });
        glActionMenu.postDelayed(new Runnable()
        {

            @Override
            public void run()
            {
                customView = new MyCustomView(MainActivity.this, fromX, fromY, toX, toY);
                rl.addView(customView);

            }
        }, 10);
    }
}
Hemantvc
  • 2,111
  • 3
  • 30
  • 42
  • Nice, this solution works! Isn't it a bit of a workaround with the postdelayed method? I think it's like guessing when the UI is drawn or am I wrong? – Serafijn Dec 25 '14 at 08:23
  • @Serafijn Not understand your question. If any query explain again? – Hemantvc Dec 25 '14 at 08:40
  • I hope I can make myself understandable. If I understand your answer, we're delaying the creation of the CustomView with 10 ms after that line of code (glActionMenu.postDelayed(new Runnable()..) is red. In reality this will always work because the UI is completely drawn whitin 10ms, but isn't there a neat solution. something like a method that gets fired when the UI is completely drawn rather then guessing by setting a runnable with a 10ms delay? – Serafijn Dec 25 '14 at 08:49
  • @Serafijn Find solution? Code share. –  Dec 25 '14 at 09:54
  • added solution at the end of my question – Serafijn Dec 25 '14 at 10:30