title: Custom Draw Line Between Two Views Not Working Properly
body: <p>I am trying to draw lines between buttons in android. I created one custom class which draw line between buttons inside relative layout(Relative Layout is parent layout).</p>
  
  <blockquote>
    <p>Here is my MatchTheColoumnDrawView.java class which accepts context, startView, endView, lineColour, endCircleColour, thickness(in float), direction(LEFT_TO_RIGHT OR RIGHT_TO_LEFT).</p>
  </blockquote>
  
  <pre><code>import android.content.Context;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.DashPathEffect;
  import android.graphics.Paint;
  import android.graphics.Path;
  import android.util.Log;
  import android.view.View;
  
  /**
   * Created by Abhishek on 12/21/2016.
   *
   * Changes made as per new design on Date 9 Oct 2017
   *
   */
  
  public class MatchTheColumnDrawView extends View {
  
  
      public static final int LEFT_TO_RIGHT = 1, RIGHT_TO_LEFT = 2;
  
      private Paint mLinePaint, mCirclePaint;
  
      private View startView, endView;
  
      private int direction;
  
      private Canvas canvas;
  
      private float dashWidth = 15f;
  
      private float dashGap = 8f;
  
      float[] intervals = new float[]{dashWidth, dashGap};
  
      float phase = 0;
  
      private int LINE_COLOR = Color.parseColor("#BEBEBE");
  
      private int END_CIRCLE_COLOR = Color.parseColor("#FF99CC00");
  
      /**
       *
       * parametrised constructor draws line from
       * @startView
       * to
       * @endView
       * as per
       * @direction
       * and
       * @lineColor
       * and
       * @endCircleColor
       *
       * when
       * @lineColor == null
       * default lineColor is gray
       *
       * when
       * @endCircleColor == null
       * default endCircleColor is green
       * */
  
      public MatchTheColumnDrawView(Context context,
                                    View startView, View endView,
                                    String lineColor, String endCircleColor,
                                    float thickness, int direction) {
  
          super(context);
  
          mLinePaint = new Paint();
          if (lineColor != null) LINE_COLOR = Color.parseColor(lineColor);
          mLinePaint.setColor(LINE_COLOR);
          mLinePaint.setStrokeWidth(thickness);
          mLinePaint.setStyle(Paint.Style.STROKE);
  
          mCirclePaint = new Paint();
          if (endCircleColor != null) END_CIRCLE_COLOR = Color.parseColor(endCircleColor);
          mCirclePaint.setColor(END_CIRCLE_COLOR);
          mCirclePaint.setStrokeWidth(thickness);
  
          this.startView = startView;
          this.endView = endView;
          this.direction = direction;
  
          //setBackgroundColor To Transparent
          super.setBackgroundColor(Color.TRANSPARENT);
      }
  
      public View getStartView() {
          return startView;
      }
  
      public void setStartView(View startView) {
          this.startView = startView;
      }
  
      public View getEndView() {
          return endView;
      }
  
      public void setEndView(View endView) {
          this.endView = endView;
      }
  
      public Canvas getCanvas() {
          return canvas;
      }
  
      public int getDirection() {
          return direction;
      }
  
      public void setDirection(int direction) {
          this.direction = direction;
      }
  
      @Override
      protected void onDraw(Canvas canvas) {
  
          this.canvas = canvas;
  
          Log.d("Direction", String.valueOf(direction));
  
          Log.d("Start View Y:", String.valueOf(startView.getY()));
          Log.d("Start View H:", String.valueOf(startView.getHeight()));
  
          Log.d("End View Y:", String.valueOf(endView.getY()));
          Log.d("End View H:", String.valueOf(endView.getHeight()));
  
          //By default takes LEFT_TO_RIGHT
  
          if (direction == RIGHT_TO_LEFT) {
  
              //For RIGHT TO LEFT
              //Calculating Left X And Mid Of Height Y
              /*
              *                   ______________
              *                  |              |
              * This Point ==&gt;&gt; .|              |
              *                  |              |
              *                  |______________|
              * */
  
              float startViewLeftX = startView.getX();
              float startViewMidHeightY = startView.getY() + startView.getHeight() / 2;
  
              //Calculating Right X And Mid Of Height Y
              /*
              *     ______________
              *    |              |
              *    |              |.  &lt;&lt;== This Point
              *    |              |
              *    |______________|
              * */
  
              float endViewRightX = endView.getX() + endView.getWidth(); //20 is just to remove unwanted padding on Right Side
              float endViewMidHeightY = endView.getY() + endView.getHeight() / 2;
  
              Path mPath = new Path();
  
              mPath.moveTo(startViewLeftX, startViewMidHeightY);
              mPath.lineTo(endViewRightX, endViewMidHeightY);
  
              DashPathEffect dashPathEffect = new DashPathEffect(intervals, phase);
  
              mLinePaint.setPathEffect(dashPathEffect);
  
              canvas.drawPath(mPath, mLinePaint);
  
              //canvas.drawLine(startViewLeftX, startViewMidHeightY, endViewRightX, endViewMidHeightY, mLinePaint);
              canvas.drawCircle(startViewLeftX, startViewMidHeightY, 5, mCirclePaint);
              canvas.drawCircle(endViewRightX, endViewMidHeightY, 5, mCirclePaint);
          } else {
  
              //FOR LEFT_TO_RIGHT
              //Calculating Right X And Mid Of Height Y
              /*
              *     ______________
              *    |              |
              *    |              |.  &lt;&lt;== This Point
              *    |              |
              *    |______________|
              * */
  
              float startViewRightX = startView.getX() + startView.getWidth(); //20 is just to remove unwanted padding on Right Side
              float startViewMidHeightY = startView.getY() + startView.getHeight() / 2;
  
              //Calculating Left X And Mid Of Height Y
              /*
              *                   ______________
              *                  |              |
              * This Point ==&gt;&gt; .|              |
              *                  |              |
              *                  |______________|
              * */
  
              float endViewLeftX = endView.getX();
              float endViewMidHeightY = endView.getY() + endView.getHeight() / 2;
  
              Path mPath = new Path();
  
              mPath.moveTo(startViewRightX, startViewMidHeightY);
              mPath.lineTo(endViewLeftX, endViewMidHeightY);
  
              DashPathEffect dashPathEffect = new DashPathEffect(intervals, phase);
  
              mLinePaint.setPathEffect(dashPathEffect);
  
              canvas.drawPath(mPath, mLinePaint);
              //canvas.drawLine(startViewRightX, startViewMidHeightY, endViewLeftX, endViewMidHeightY, mLinePaint);
              canvas.drawCircle(startViewRightX, startViewMidHeightY, 5, mCirclePaint);
              canvas.drawCircle(endViewLeftX, endViewMidHeightY, 5, mCirclePaint);
          }
      }
  
      @Override
      public void setBackgroundColor(int color) {
          super.setBackgroundColor(color);
      }
  
  
  }
  </code></pre>
  
  <blockquote>
    <p>I wrote one class MatchTheFollowingAttempted which extend Relative layout and it contains logic for drawing buttons and lines between them. Here is MatchTheFollowingAttempted.java class.</p>
  </blockquote>
  
  <pre><code>import android.content.Context;
  import android.util.AttributeSet;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.Button;
  import android.widget.RelativeLayout;
  
  import java.util.ArrayList;
  
  /**
   * Created by Abhishek on 24-10-2017.
   */
  
  public class MatchTheFollowingAttempted extends RelativeLayout {
  
      private Context mContext;
  
      int numberOfOneSideButtons = 5;
  
  
      public MatchTheFollowingAttempted(Context context) {
          super(context);
          mContext = context;
          initialiseView();
      }
  
      public MatchTheFollowingAttempted(Context context, AttributeSet attrs) {
          super(context, attrs);
          mContext = context;
          initialiseView();
      }
  
      public MatchTheFollowingAttempted(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          mContext = context;
          initialiseView();
      }
  
      public MatchTheFollowingAttempted(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
          super(context, attrs, defStyleAttr, defStyleRes);
          mContext = context;
          initialiseView();
      }
  
      public void initialiseView() {
  
          ArrayList&lt;Button&gt; leftSideButtons = new ArrayList&lt;&gt;();
          ArrayList&lt;Button&gt; rightSideButtons = new ArrayList&lt;&gt;();
          ArrayList&lt;MatchTheColumnDrawView&gt; matchTheColumnDrawViewArrayList = new ArrayList&lt;&gt;();
  
  
          for (int i = 0; i &lt; numberOfOneSideButtons; i++) {
  
              Button mButton = new Button(mContext);
  
              mButton.setId(View.generateViewId());
  
              RelativeLayout.LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  
              if (i != 0) {
  
                  layoutParams.addRule(BELOW, leftSideButtons.get(i-1).getId());
  
              }
  
              layoutParams.setMargins(10, 10, 10, 10);
  
              mButton.setLayoutParams(layoutParams);
  
              leftSideButtons.add(mButton);
  
              addView(mButton);
  
  
          }
  
          for (int i = 0; i &lt; numberOfOneSideButtons; i++) {
  
              Button mButton = new Button(mContext);
  
              mButton.setId(View.generateViewId());
  
              RelativeLayout.LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  
              layoutParams.addRule(ALIGN_PARENT_RIGHT);
  
              if (i != 0) {
  
                  layoutParams.addRule(BELOW, rightSideButtons.get(i-1).getId());
  
              }
  
              layoutParams.setMargins(10, 10, 10, 10);
  
              mButton.setLayoutParams(layoutParams);
  
              rightSideButtons.add(mButton);
  
              addView(mButton);
  
          }
  
          for (int i = 0; i &lt; numberOfOneSideButtons; i++) {
  
              MatchTheColumnDrawView matchTheColumnDrawView = new MatchTheColumnDrawView(mContext, leftSideButtons.get(i), rightSideButtons.get(4-i), null, null, 2.0f, MatchTheColumnDrawView.LEFT_TO_RIGHT);
  
              matchTheColumnDrawViewArrayList.add(matchTheColumnDrawView);
  
              addView(matchTheColumnDrawView);
          }
  
  
  
      }
  
  }
  </code></pre>
  
  <blockquote>
    <p>When I directly use MatchTheFollowingAttempted inside LinearLayout(Inside Scrollview) it will shows view properly with buttons and lines between them. As shown in image attached(Image_One). Here is the xml for it. </p>
  </blockquote>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"&gt;
  
      &lt;ScrollView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:fillViewport="true"&gt;
  
          &lt;LinearLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"&gt;
  
              &lt;MatchTheFollowingAttempted
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"&gt;
  
              &lt;/MatchTheFollowingAttempted&gt;
  
          &lt;/LinearLayout&gt;
  
      &lt;/ScrollView&gt;
  
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/EuWDw.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/EuWDw.jpg" alt="Image_One"></a></p>
  
  <blockquote>
    <p>But when I add second MatchTheFollowingAttempted in Linear Layout Then Lines will not shown(As in attached image Image_Two). Here is xml with two MatchTheFollowingAttempted in Linear Layout.</p>
  </blockquote>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:tools="http://schemas.android.com/tools"
      android:layout_width="match_parent"
      android:layout_height="match_parent"&gt;
  
      &lt;ScrollView
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:fillViewport="true"&gt;
  
          &lt;LinearLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"&gt;
  
              &lt;MatchTheFollowingAttempted
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"&gt;
  
              &lt;/MatchTheFollowingAttempted&gt;
  
              &lt;MatchTheFollowingAttempted
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"&gt;
  
              &lt;/MatchTheFollowingAttempted&gt;
  
          &lt;/LinearLayout&gt;
  
      &lt;/ScrollView&gt;
  
  &lt;/RelativeLayout&gt;
  </code></pre>
  
  <p><a href="https://i.stack.imgur.com/fM4PQ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/fM4PQ.png" alt="Image_Two"></a></p>
  
  <blockquote>
    <p>When I run it real its not showing second layout.</p>
  </blockquote>