3

I have an app that is a collection of youth Christian songs, and now I want to add chords. So, say I have the following line in a .txt file:

     D         G             D            

Amazing grace! How sweet the sound

This is what always happens when the line doesn't fit on screen:

D

G D

Amazing grace!

How sweet the sound

I want this to happen:

D

Amazing grace!

G D

How sweet the sound!

Sorry for not being clear, I really hope that made sense. I have seen other apps do that, but I don't know how to do it.

Edit:

I have my songs structured like this:

[chords for phrase]

[phrase]

Eddie
  • 171
  • 5
  • 13

2 Answers2

2

I'm a little confused about your present text file(s) and their format. I understand your required behavior. Your implementation will need to use the separation of chords and lyrics to affect the wrapping. Therefore, delineating chords and lyrics is necessary. I will focus on the logic and design rather than specific implementation of my possible solutions. Please comment with further concerns.

Problematic Format:

[----1st phrase chords----][----1st phrase lyrics----][----2nd phrase chords----][----2nd phrase lyrics----]

If this is the case, you may have trouble, since you won't be able to know where the lyrics begin when your first line of chords is full. For example, see the pseudocode below:

String textFile = //your song
while textFile has characters left
   fill a line of the TextView with chords
   fill the next line of the TextView with the associated lyrics
endwhile

The second line within the while-loop can't be performed, since you don't know where the lyrics begin. You may need to manually adjust your files to be in the format of the second design, since they were probably manually spaced to fit this format (if this format).

Fixed Formats:

These formats acknowledge and fix the problem of logically separating chords and lyrics. One format:

[----1st phrase chords----]
[----1st phrase lyrics----]
[----2nd phrase chords----]
[----2nd phrase lyrics----]

where you would read each line into separate Strings, or another with two separate files:

chords.txt:

[----1st phrase chords----]
[----2nd phrase chords----]

lyrics.txt:

[----1st phrase lyrics----]
[----2nd phrase lyrics----]   

I say text files, but it could be data received through a network request, etc.

Once you've split your chords and lyrics, there may be a more Android-specific solution for TextViews, but I have two ideas for work-arounds.

The first workaround could calculate the number of characters fitting in a single line of your TextViews and split the text accordingly. I.e.:

Discover a line of the TextView holds X monospaced characters
While the chords and lyrics aren't exhausted
    Fill a new TextView line with X characters of chords
    Fill a new TextView with X characters of lyrics
Endwhile

Another possible work-around could use two TextViews with double (or greater) line-spacing and placing them on-top of each other. You could have one TextView hold chords and the other hold lyrics, with an extra line of whitespace at the top of the lyrics. Here's my attempt at an illustration:

.      First TextView           below          Second TextView
[----1st phrase chords      ----]   [----Whitespace added manually ----]
[----Line-spacing whitespace----]   [----1st phrase lyrics         ----]
[----2nd phrase chords      ----]   [----Line-spacing whitespace   ----]
[----Line-spacing whitespace----]   [----2nd phrase lyrics         ----]

Important Consideration:

You will want to use a monospaced font. This will mean all characters are the same width. Otherwise, the specific characters will affect the number fitting in each line.

Matt Goodrich
  • 4,875
  • 5
  • 25
  • 38
  • 1
    Thank you for such a great response! I think I will use the second solution, just because it's easier for me. One thing though; Android Studio automatically erases all the whitespace at the end of `.txt` files, and I am guessing both the lyrics and the chord lines have to be the same length, otherwise one line might fit, and not the other one. One more thing; is there a chance that double spacing might not work with different device screens? – Eddie May 10 '17 at 23:58
  • No problem @Eddie, I'm glad I can help. For the whitespace being erased, please see this question http://stackoverflow.com/questions/42591525/android-studio-automatically-erases-extra-spaces-in-txt-files/42591798. If that doesn't help, you could include another file with the length of the txt files, and append whitespace to the end of the strings from saved files as you place them in the `TextViews`. The length could be saved with other song metadata. Please let me know if you still have trouble. [cont] – Matt Goodrich May 11 '17 at 00:14
  • Multiple device widths should not be a problem. If you use a scrollable element with the `TextViews` inside (I don't remember the name for Android), then height shouldn't be a problem either. – Matt Goodrich May 11 '17 at 00:14
  • @akash93 gave a great response with implementation details and may be able to provide insight for your follow-up questions as well. – Matt Goodrich May 11 '17 at 00:17
  • Would it work if I just compare the lengths of the chord and the lyrics lines, and add the needed spaces directly to the string holding the line of chords/lyrics – Eddie May 11 '17 at 00:18
  • Definitely, that's a better than solution than what I stated above! – Matt Goodrich May 11 '17 at 00:19
  • @Eddie you don't need to add spaces at all. That can be taken care of by wrapping the 2 TextViews inside a linear layout and setting `layout_gravity="center_horizontal"` for the first TextView. Check my updated answer. – ashkhn May 11 '17 at 02:10
  • It seems that setting the `TexView` to be mono spaced only affects english letter. The app I have mostly includes Russian songs, so only the chord `TextView` is monospaced – Eddie May 13 '17 at 03:59
  • @Eddie have you tried the solution I posted? You don't need monospaced font for it to work.. – ashkhn May 13 '17 at 13:06
2

Matt has given an excellent explanation regarding how your data should be structured. I'll just add the implementation details.

Assuming the input data is in the following format:

[ChordName] [Phrase for the chord]

You can use a horizontal RecyclerView to display the data. The layout for each item would look like

<LinearLayout 
android:layout_height="match_parent"
android:layout_width="wrap_content"
android:orientation="vertical">
   <TextView 
     android:id="@+id/tv_chord_name"
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
     android:layout_gravity="center_horizontal"
     />
   <TextView
     android:layout_height="wrap_content"
     android:layout_width="wrap_content"
     android:id="@+id/tv_phrase"/>
</LinearLayout>

I've only added a few attributes to showcase the structure. You can use layout_gravity="center_horizontal" for the first text view to center align the chord name with the lyric.

The way this works is that the width of the LinearLayout is set to wrap_content which means effectively it will be the same as the length of the longest child which will be the 2nd TextView in your case.

Now layout_gravity="center_horizontal" will center the first TextView automatically based on the length of the LinearLayout which is exactly what you need. So no need for adding whitespaces to align the content

ashkhn
  • 1,642
  • 1
  • 13
  • 18
  • It's a `Linear Layout`, so I can't have the 2 `TextViews` overlap each other – Eddie May 13 '17 at 02:43
  • What do you mean? It's a vertical `LinearLayout` so the TextViews will be one below the other.. – ashkhn May 13 '17 at 13:01
  • Sorry. I think there is a misunderstanding... If I have the `TextViews` below each other, then I will need a `TextView` for each line of chords and each line of lyrics?.. Other wise it will just be all the chords in the first `TextView` and all the lyrics in the second – Eddie May 14 '17 at 16:57
  • Yes you'll need a `TextView` for each chord and each line. Like I said in my answer it's going to be a horizontal `RecyclerView` where each list item is one chord and the lyric associated with that chord. This way you don't need to worry about spacing or font style or alignment. – ashkhn May 15 '17 at 00:57
  • Yeah that's exactly how you need them to be structured for this to work.. I'm not really understanding what problem you're facing – ashkhn May 15 '17 at 05:29
  • There's a few things that I don't fully understand. `1`I am not familiar with `RecyclerView` (I know what it does, but not how to work with it)`2` if I have a phrase of lyrics that only needs one chord in the beginning of it, and I set `android:layout_gravity ="center_horizontal"`, won't the chords go in the middle and not the beginning of the line – Eddie May 16 '17 at 01:31
  • 1) `RecyclerView` is an improved version of `ListView` used for showcasing repeating items. In this case the repeating unit is a chord name and the lyric associated with it. 2) Yes they will go in the middle above the lyric line which in my opinion makes sense for viewing longer lyric lines having the same chord. – ashkhn May 16 '17 at 02:00
  • Okay I see! I will use this and accept this answer once i can make sure it works good!! But how would it look in `XML` and `Java`? Can I use `android.support.v7.widget.RecyclerView` instead of just a `RecyclerView` to make it compatible with some older devices?? And would I still `import android.windget.RecycletView` or something else? Could you also help me with the `java` part it would be great! – Eddie May 16 '17 at 02:35
  • I've already posted the XML layout for the list item. For the java code you can refer to any `RecyclerView` tutorial for implementation since it will have a lot of boilerplate code. [Example](https://guides.codepath.com/android/using-the-recyclerview) – ashkhn May 16 '17 at 10:02
  • Well, what if the whole phrase doesn't fit into one line – Eddie May 17 '17 at 20:31
  • It's a horizontal `RecyclerView` so that shouldn't be a problem at all – ashkhn May 19 '17 at 00:57
  • What would happen if it doesnt – Eddie May 19 '17 at 23:26
  • Nothing at all? I'm not sure if you understand what a horizontal `RecylerView` is.. It is a horizontally scrolling view so the content being longer than 1 line is never going to happen.. – ashkhn May 20 '17 at 12:21
  • The lyric line doesn't fit into one line on screen, so it moves to the next, but the chord just stays at the end of the line, and doesn't move to the next line – Eddie May 22 '17 at 20:15
  • Yes.. I'm not sure what the problem is? The user scrolls the list and plays the same chord until they see a new chord. If you're trying to show them the chord name on every screen you'll have to pre-process your data and impose a word limit on the lyric lines. Then break up the lyrics and add extra instances of the same chord name – ashkhn May 23 '17 at 01:21
  • Look, I want the chord `D` to be over the word `sing`, even if the word `sing` has to go to the next line. But the way I have it now the chord `D` stays at the end of the previous line, but the word` sign` goes to the new line – Eddie May 23 '17 at 02:07
  • I'm not sure you understand the implementation yet.. There cannot be a word going on the next line since this is a horizontally scrolling view... Since I can't see the word `sing` anywhere in the question I'm assuming you mean the word `sound`. Assuming the lyrics for `D` are `the sound` the above layout will ensure that `D` gets placed above `the` without setting `layout_gravity` and somewhere between `the` and `sound` if you set it. You've explicitly stated that you want the chord name at the beginning of the lyric line in a previous comment so I'm not sure what your requirements are.. – ashkhn May 23 '17 at 03:29