I'm creating a notes app and I keep running into a problem with Spannable strings
What I'm trying to achieve is when I'm typing in a note and i click a button, i want it to add a big, bold string into the EditText field which has been achieved with the help of spannable strings. the problem im having now is when i save the note and exit, then go back into the note, the spannable string are still there but are no longer big and bold.
Is there a way to save the spannable strings? if not, is there any way to get this same effect?
also side note: i was wondering if theres a way to make the text of the spannable string one object. so when i erase it, it erases all together. not each letter like regular text.
Here's the button in my NoteActivity:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.save_note:
save_note();
return true;
case android.R.id.home:
save_note();
finish();
return true;
case R.id.add_intro:
SpannableString intro;
if (note_content.length() == 0) {
intro = new SpannableString("(Intro:)\n");
intro.setSpan(new StyleSpan(Typeface.BOLD), 0, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
intro.setSpan(new RelativeSizeSpan(1.25f), 0, 8, 0);
} else {
intro = new SpannableString("\n\n(Intro:)\n");
intro.setSpan(new StyleSpan(Typeface.BOLD), 0, 11, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
intro.setSpan(new RelativeSizeSpan(1.25f), 0, 11, 0);
}
note_content.append(intro);
return true;
and here's how the notes being saved and loaded Utilities
public class Utilities {
public static final String FileExtention = ".bin";
public static boolean save_note(Context context, Note note) {
String fileName = String.valueOf(note.getDateTime()) + FileExtention;
FileOutputStream fos;
ObjectOutputStream oos;
try {
fos = context.openFileOutput(fileName, context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(note);
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
public static ArrayList<Note> getAllSavedNotes(Context context) {
ArrayList<Note> notes = new ArrayList<>();
File filesDir = context.getFilesDir();
ArrayList<String> noteFiles = new ArrayList();
for(String file : filesDir.list()) {
if(file.endsWith(FileExtention)) {
noteFiles.add(file);
}
}
FileInputStream fis;
ObjectInputStream ois;
for(int i = 0; i < noteFiles.size(); i++) {
try{
fis = context.openFileInput(noteFiles.get(i));
ois = new ObjectInputStream(fis);
notes.add((Note)ois.readObject());
fis.close();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
return null;
}
}
return notes;
}
heres the NoteAdapter
public class NoteAdapter extends ArrayAdapter<Note> {
public NoteAdapter(Context context, int resource, ArrayList<Note> notes) {
super(context, resource, notes);
}
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
//return super.getView(position, convertView, parent);
if(convertView == null) {
convertView = LayoutInflater.from(getContext())
.inflate(R.layout.item_note, null);
}
Note note = getItem(position);
if(note != null) {
TextView title = (TextView) convertView.findViewById(R.id.list_note_title);
TextView content = (TextView) convertView.findViewById(R.id.list_note_content);
TextView date = (TextView) convertView.findViewById(R.id.list_note_date);
Typeface music_font = Typeface.createFromAsset(getContext().getAssets(), "fonts/melodymakernotesonly.ttf");
Typeface scribble_card = Typeface.createFromAsset(getContext().getAssets(), "fonts/the unseen.ttf");
title.setTypeface(music_font);
content.setTypeface(scribble_card);
title.setText(note.getTitle());
date.setText(note.getDateTimeFormatted(getContext()));
if(note.getContent().length() > 25) {
content.setText(note.getContent().substring(0,25) + "...");
} else {
content.setText(note.getContent());
}
if(note.getContent().length() <= 0) {
content.setText("(Empty Note..)");
} else {
content.setText(note.getContent());
}
if (note.getTitle().length() <= 0) {
title.setText("(Untitled)");
} else {
title.setText(note.getTitle());
}
}
return convertView;
}
and here my Note class
public class Note implements Serializable {
private long mDateTime;
private String mTitle;
private String mContent;
public Note(long dateTime, String title, String content) {
mContent = content;
mTitle = title;
mDateTime = dateTime;
}
public void setDateTime(long dateTime) {
mDateTime = dateTime;
}
public void setTitle(String title) {
mTitle = title;
}
public void setContent(String content) {
mContent = content;
}
public long getDateTime() {
return mDateTime;
}
public String getTitle() {
return mTitle;
}
public String getContent() {
return mContent;
}
public String getDateTimeFormatted(Context context) {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:SS", context.getResources().getConfiguration().locale);
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(new Date(mDateTime));
}
The information of the spans is lost when you convert the SpannableString to a normal String (like your Note.mContent). The spans used by SpannableString are nothing like HTML tags. You can think of them as additional information to the actual string.
Lets take this string:
Hi, I am a bold string.
In the markdown used here on SO this looks like so:
Hi, I am a **bold** string.
In HTML it looks like so:
Hi, I am a <strong>bold</strong> string.
However, as a SpannableString is a structure something like this:
Text : Hi, I am a bold string.
Span : Render characters [11..14] in bold
So there is the actual text and the additional information, which parts of the text to render in bold.
If you want to preserve that information, you can either use the basic HTML support, Android provides and use a string like "Hi, I am a <b>bold</b> string." or you have to save the format info additionally to the text content.
EDIT
To use strings with HTML you have to use Html.fromHtml():
textView.setText(Html.fromHtml(getString(R.string.your_html_string)));
Saving format information means, that you'd have to extend your Note class to store the formatting information, basically the spans you applied to the string. For example you could use something like this:
class FormatInfo {
int from;
int to;
int formatCode; // <-- e.g. 1 = bold, 2 = italic etc.
}
class FormattedNote extends Note {
List<FormatInfo> formatInfos = new ArrayList<>();
}
And then you'd have to convert the spans you applied to FormatInfo objects and add them to the FormattedNote when saving a note and when creating the SpannableString again, you'd have to create the spans from the formatInfos of the note.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With