0

I'm trying to draw a line under a TextView (creating a rubber bridge score sheet, where the lines in question mirror the dotted lines here). I can't figure out how to get the position of the bottommost TextView and use those numbers to create a line in the proper position. The line is currently far below the TextView that it should be immediately below, i.e.:

40
——— <---- I want this (close to number)

40

——— <---- I get this (farther from number)

The line does change position depending on the vertical position of the bottommost TextView, so i think i am successfully retrieving its position, but somehow i'm not using it properly to draw the line.

Here's the code getting the position of the TextView and sending it to the line drawing method:

    findViewById(R.id.main).getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    //remove listener
                    if( Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN )
                        findViewById(R.id.main).getViewTreeObserver()
                                .removeOnGlobalLayoutListener(this);
                    else
                        findViewById(R.id.main).getViewTreeObserver()
                                .removeGlobalOnLayoutListener(this);

                    TextView bottomTextView = (TextView) weGameLayout
                            .getChildAt(weGameLayout.getChildCount() - 1);
                    int[] pos = new int [2];
                    bottomTextView.getLocationOnScreen(pos);
                    int gameLinePosition = pos[1];
                    int height = bottomTextView.getHeight();
                    ((BackgroundLines)findViewById(R.id.background_lines))
                            .addGameLine(gameLinePosition + height - topdiff);
                }
            }
    );

And here's the line drawing method:

public void addGameLine(int position) {
    ShapeDrawable line = new ShapeDrawable(new RectShape());
    gameLines.add(line);
    gameLinePositions.add(position);
    invalidate();
}
@Override
public void onDraw(Canvas canvas) {
    int width = this.getWidth();
    for( int i=0; i < gameLines.size(); ++i ){
        ShapeDrawable gameLine = gameLines.get(i);
        int position = gameLinePositions.get(i);
        gameLine.setBounds(0, position-2, width, position+2);
        gameLine.draw(canvas);
    }
}

Let me know if any more info is useful! It seems like a subtle problem and is a little tough to describe, but i think my ignorance of android's layout or drawing management is mostly at fault.

EDIT here's the main layout. It's long, but almost all the relevant stuff is right at the top i think

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

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:elevation="4dp"
        android:theme="@style/ThemeOverlay.AppCompat.ActionBar" />

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:background="@drawable/parchment_scroll_background"
        tools:context="com.pianomansb.betterbridgescoresheet.MainActivity">

        <com.pianomansb.betterbridgescoresheet.BackgroundLines
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/background_lines" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <LinearLayout
                android:id="@+id/we_column"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <LinearLayout
                    android:id="@+id/we_upper"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/we_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:text="@string/we_text"
                        style="@style/WeTheyFont"/>

                    <LinearLayout
                        android:id="@+id/we_bonus"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical"
                        android:gravity="bottom">

                    </LinearLayout>

                </LinearLayout>

                <LinearLayout
                    android:id="@+id/we_game"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                </LinearLayout>

            </LinearLayout>

            <LinearLayout
                android:id="@+id/they_column"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <LinearLayout
                    android:id="@+id/they_upper"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/they_text"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:text="@string/they_text"
                        style="@style/WeTheyFont"/>

                    <LinearLayout
                        android:id="@+id/they_bonus"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:orientation="vertical"
                        android:gravity="bottom">

                    </LinearLayout>

                </LinearLayout>

                <LinearLayout
                    android:id="@+id/they_game"
                    android:layout_width="match_parent"
                    android:layout_height="0dp"
                    android:layout_weight="1"
                    android:orientation="vertical">

                </LinearLayout>

            </LinearLayout>
        </LinearLayout>
    </FrameLayout>
</LinearLayout>
sam
  • 97
  • 9
  • do you have a layout xml? – Gavriel Feb 07 '16 at 23:20
  • I'll post it, although it's kinda long. Not sure how much of it is relevant – sam Feb 07 '16 at 23:24
  • Basically, i'm using a FrameLayout to layer the main layout (all the LinearLayouts and stuff) on top the BackgroundLines custom layout that i'm using for drawing the lines. I thought that would be an easy way to set it up, since trying to piece together a layout including a bunch of weirdly shaped views containing the lines would be pretty complicated – sam Feb 07 '16 at 23:29
  • Did you try a relativelayout? – Gavriel Feb 07 '16 at 23:33
  • Briefly at the start of the project, but this approach seemed easier at the time. Do you think it would be better to restructure it as a relativelayout with the lines in the same layer as the text? – sam Feb 07 '16 at 23:39
  • that was my 1st thought when I saw the ASCII graphics about what widgets need to be close to each other – Gavriel Feb 07 '16 at 23:42
  • As a suggestion for an alternative approach: Why not extend from `TextView`, override `onDraw` and add your dotted lines there. This would also make the global listeners superfluous. Or, at least, put your `BackgroundLines` widget to where it belongs in your xml (after the `TextView`) so that you don't have to mess around with bounds and heights. – Taig Feb 08 '16 at 01:05
  • Thanks for the reply! In an effort to be streamlined, i left out extra information about the project: `BackgroundLines` contains the solid lines also in the linked .png, which is why i took it out of the normal layout flow in the first place. But you might be right that the easiest thing to do would be to incorporate the dotted lines into the stack of TextViews directly. – sam Feb 08 '16 at 01:56

1 Answers1

1

It sounds like you're trying to something more complicated than the usual view layout tools let you do. I won't tell you to stop trying that way, but I would recommend a completely different approach that might be easier for you.

I would make the entire thing a custom view (unless it can be very tall, then it might be whole different issue. Make sure your View subclass advertises its preferred height and width properly.

In the onDraw draw the lines on the Canvas like you normally would. Note that you can also draw text on a Canvas without the need for a TextView. Simply use Canvas.drawText() to position the text the way you want, and use that method's Paint parameter to size and color the text.

I hope that proves to be a better strategy for you.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441