Search code examples
javaandroidkotlinandroid-layoutandroid-view

Add dots to a TextView like in a receipt


I want to implement something like a product list in a receipt:
Bread ......................................... 20
Milk ............................................ 10
Cookies with jam ...................... 15
Smartphone 10GB 3GHz
1GB RAM NFC 10MPx
camera .................................... 400

Item name (Bread, Milk) I think it shoud be a TextView, which I need to fill with dots.
Money (20, 10) is another TextView which shoud be aligned to the right of a screen.

Any ideas how to do this? Maybe I need to inherit the TextView class and override onDraw()?
Many thanks in advance!


Solution

  • I have the solution. Maybe it will help someone.

    1. File check_info_item.xml:

      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
      <RelativeLayout android:layout_width="match_parent"
                android:layout_height="wrap_content">
      
      <TextView android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:id="@+id/txt_fake_value"
                android:textSize="18dp"
                android:textColor="@android:color/transparent"
                android:layout_alignParentRight="true"/>
      <example.com.CheckInfoTextView android:layout_height="wrap_content"
                android:layout_width="match_parent"
                android:id="@+id/txt_fake_info"
                android:textSize="18dp"
                android:textColor="@android:color/transparent"
                android:layout_alignParentLeft="true"
                android:layout_toLeftOf="@id/txt_fake_value"/>
      <TextView android:layout_height="wrap_content"
                android:layout_width="wrap_content"
                android:id="@+id/txt_check_info_value"
                android:text=""
                android:textSize="18dp"
                android:textColor="#000"
                android:layout_alignParentRight="true"
                android:layout_alignBottom="@id/txt_fake_info"/>
      <example.com.CheckInfoTextView
              android:layout_height="wrap_content"
              android:layout_width="match_parent"
              android:textSize="18dp"
              android:textColor="#000"
              android:id="@+id/txt_check_info"
              android:text=""
              android:layout_alignParentLeft="true"
              android:layout_toLeftOf="@id/txt_check_info_value"/>
      </RelativeLayout>
      </LinearLayout>
      
    2. Code to fill the info fields (in the Activity):

          View row = getLayoutInflater().inflate(R.layout.check_info_item, null);
          //Fake fields needed to align base fields in the xml file
          TextView txtFakeValue = (TextView) row.findViewById(R.id.txt_fake_value);
          txtFakeValue.setText(String.valueOf(pair.second));
      
          TextView txtFake = (TextView) row.findViewById(R.id.txt_fake_info);
          txtFake.setText(pair.first);
      
          TextView txtValue = (TextView) row.findViewById(R.id.txt_check_info_value);
          txtValue.setText(String.valueOf(pair.second));
      
          TextView txtTitle = (TextView) row.findViewById(R.id.txt_check_info);
          txtTitle.setText(pair.first);
      
    3. And the CheckInfoTextView:

      public class CheckInfoTextView extends TextView {
      
      
          public CheckInfoTextView(Context context) {
              super(context);
          }
      
          public CheckInfoTextView(Context context, AttributeSet attrs) {
              super(context, attrs);
          }
      
          public CheckInfoTextView(Context context, AttributeSet attrs, int defStyle) {
              super(context, attrs, defStyle);
          }
      
          @Override
          public void onWindowFocusChanged(boolean hasWindowFocus) {
              super.onWindowFocusChanged(hasWindowFocus);
              if(!hasWindowFocus) return;
      
              int requiredDots = getRequiredDotsNumber();
              if(requiredDots == 0) {
                  String text = getText().toString();
                  StringBuilder result = new StringBuilder();
                  result.append(text.substring(0, text.lastIndexOf(' ')));
                  result.append("\n");
                  result.append(text.substring(text.lastIndexOf(' ') + 1));
                  setText(result.toString());
      
                  requiredDots = getRequiredDotsNumber();
              }
              String dots = "";
              for (int i = 0; i < requiredDots; ++i) {
                  dots += " .";
              }
              setText(getText() + dots);
          }
      
          private int getRequiredDotsNumber() {
              final int width = getWidth();
              final int lastLineWidth = (int) getLayout().getLineWidth(getLineCount() - 1);
              final int availableWidthForDots = width - lastLineWidth;
              final int widthOfOneDot = getWidthOfOneDot();
              final int widthOfTwoDotsWithSpace = getWidthOfTwoDotsWithSpace();
              final int widthOfSpace = widthOfTwoDotsWithSpace - (widthOfOneDot * 2);
              final int widthOfDotWithSpace = widthOfSpace + widthOfOneDot;
              int numberOfDots = availableWidthForDots / widthOfDotWithSpace;
              return numberOfDots;
          }
      
          private int getWidthOfTwoDotsWithSpace() {
             return getStringWidth(". .");
          }
      
          private int getWidthOfOneDot() {
             return getStringWidth(".");
          }
      
          private int getStringWidth(String text) {
              Rect dotBounds = new Rect();
              getPaint().getTextBounds(text,0,text.length(),dotBounds);
              return dotBounds.width();
          }
      }