So as you may know the screen space on Google Glass is limited. The Mirror API has a nice "Read more" feature whereby cards with long text are converted into multiple cards through which the user can scroll. I've been trying to achieve the same effect with text in the GDK to no avail.
So the question is, quite simply, how do I display long text to the user with GDK? This is really vital for reading news articles, for instance.
UPDATE: not finding anything currently available, I've created an activity for automatically splitting up text into multiple cards. It's not ideal so hopefully someone can improve upon it. The interface is to start an activity with a class intent and text
extra:
case R.id.read_more:
intent = new Intent(this, ReadMoreActivity.class);
intent.putExtra(ReadMoreActivity.TEXT, text);
startActivity(intent);
return true;
This calls the ReadMoreActivity
class which breaks up the text into as many cards as are needed so that the full text can be viewed. The way this is implemented, I wouldn't recommend doing a whole novel this way, but it seems to work up to a dozen or more cards worth of text:
public class ReadMoreActivity extends Activity {
public static final String TEXT = "text";
private static final boolean DEBUG = true;
private static final String TAG = ReadMoreActivity.class.getSimpleName();
private static final float SPACING_MULT = 1.0f;
private static final float SPACING_ADD = 1.0f;
private static final boolean INCLUDE_PAD = false;
private String mText;
private CardScrollView mCardScrollView;
private TextCardScrollAdapter mAdapter;
private List<Card> mCards;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null && savedInstanceState.containsKey(TEXT))
mText = savedInstanceState.getString(TEXT);
else if (getIntent() != null && getIntent().hasExtra(TEXT))
mText = getIntent().getStringExtra(TEXT);
else {
Log.e(TAG, "no text found");
finish();
return;
}
createCardsFromText();
mAdapter = new TextCardScrollAdapter();
View rootLayout = getLayoutInflater().inflate(R.layout.card_scroll_layout, null);
mCardScrollView = (CardScrollView)rootLayout.findViewById(R.id.card_scroll_view);
mCardScrollView.setAdapter(mAdapter);
mCardScrollView.activate();
setContentView(rootLayout);
}
private void createCardsFromText() {
int textSize = getResources().getDimensionPixelSize(R.dimen.card_main_layout_main_min_textSize);
int maxWidth = getResources().getDimensionPixelSize(R.dimen.card_main_layout_main_width);
int maxHeight = getResources().getDimensionPixelSize(R.dimen.card_main_layout_main_height);
TextView tv = new TextView(this);
tv.setTextSize(textSize);
tv.setText(mText);
StaticLayout measure = new StaticLayout(tv.getText(), tv.getPaint(),
maxWidth, Layout.Alignment.ALIGN_NORMAL, 1.0f, 1.0f, false);
int numLines = measure.getLineCount();
if (DEBUG) Log.i(TAG, "calculated lines=" + numLines + " for text=[" + mText + "]");
int linesPerCard = maxHeight / textSize;
int numFullCards = numLines / linesPerCard;
int numCards = numFullCards + (numLines % linesPerCard > 0 ? 1 : 0);
mCards = new ArrayList<Card>();
for (int cardNum = 0; cardNum < numCards; cardNum++) {
int startLine = cardNum * linesPerCard;
int nextStartLine = startLine + linesPerCard;
int startOffset = measure.getLineStart(startLine);
int endOffset = (nextStartLine < numLines) ? measure.getLineStart(nextStartLine) : mText.length();
String cardText = mText.substring(startOffset, endOffset);
Card card = new Card(this);
card.setText(cardText);
String cardFootnote = getString(R.string.read_more_format, cardNum + 1, numCards);
card.setFootnote(cardFootnote);
mCards.add(card);
}
}
private class TextCardScrollAdapter extends CardScrollAdapter {
@Override
public int findIdPosition(Object id) {
return -1;
}
@Override
public int findItemPosition(Object item) {
return mCards.indexOf(item);
}
@Override
public int getCount() {
return mCards.size();
}
@Override
public Object getItem(int position) {
return mCards.get(position);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return mCards.get(position).toView();
}
}
}
The layout file card_scroll_layout.xml' for this is pretty simple, just a wrapper around the
CardScrollView`:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
<com.google.android.glass.widget.CardScrollView
android:id="@+id/card_scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
The dimensions file dimens.xml
needs to know the card dimensions for the text calculation:
<dimen name="card_main_layout_main_width">560px</dimen>
<dimen name="card_main_layout_main_height">240px</dimen>
<dimen name="card_main_layout_main_min_textSize">30px</dimen>
<dimen name="card_main_layout_footnote_width">560px</dimen>
<dimen name="card_main_layout_footnote_height">40px</dimen>
Also in your strings.xml
you need something for the footnote so the users knows their position in the Read More:
<string name="read_more_format">read more ~ page %1$d of %2$d</string>