I am working on application translated to languages that are not supported - missing fonts on devices.
So I added fonts to application and changed typeface for all TextViews, EditTexts, Buttons.
Also I was able to change fonts in WebView.
But now I need to change typeface for all system components:
ActionBar:
Title Dropdown
Menu
ShareActionProvider
ActionItems
ActionItems in overflow
Dialog
Toast
Settings Screen
Is there a way to change typeface for this components.
Probably all have some TextView in them - just to know their id to find them.
Please do not post answers about changing Typeface on TextView!
Create Views with custom fonts like this
FontManager.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.graphics.Typeface;
import android.view.InflateException;
public class FontManager
{
//Making FontManager a singleton class
private static class InstanceHolder
{
private static final FontManager INSTANCE = new FontManager();
}
public static FontManager getInstance()
{
return FontManager.InstanceHolder.INSTANCE;
}
private FontManager()
{
}
// Different tags used in XML file.
private static final String TAG_FAMILY = "family";
private static final String TAG_NAMESET = "nameset";
private static final String TAG_NAME = "name";
private static final String TAG_FILESET = "fileset";
private static final String TAG_FILE = "file";
// Different styles supported.
private static final String STYLE_BOLD = "-Bold.ttf";
private static final String STYLE_ITALIC = "-Italic.ttf";
private static final String STYLE_BOLDITALIC = "-BoldItalic.ttf";
private class FontStyle
{
int style;
Typeface font;
}
private class Font
{
// different font-family names that this Font will respond to.
List<String> families;
// different styles for this font.
List<FontStyle> styles;
}
private List<Font> mFonts;
//private boolean isFamilySet = false;
private boolean isName = false;
private boolean isFile = false;
// Parse the resId and initialize the parser.
public void initialize(Context context, int resId)
{
XmlResourceParser parser = null;
try
{
parser = context.getResources().getXml(resId);
mFonts = new ArrayList<Font>();
String tag;
int eventType = parser.getEventType();
Font font = null;
do
{
tag = parser.getName();
switch ( eventType )
{
case XmlPullParser.START_TAG:
if ( tag.equals(TAG_FAMILY) )
{
// one of the font-families.
font = new Font();
}
else if ( tag.equals(TAG_NAMESET) )
{
// a list of font-family names supported.
font.families = new ArrayList<String>();
}
else if ( tag.equals(TAG_NAME) )
{
isName = true;
}
else if ( tag.equals(TAG_FILESET) )
{
// a list of files specifying the different styles.
font.styles = new ArrayList<FontStyle>();
}
else if ( tag.equals(TAG_FILE) )
{
isFile = true;
}
break;
case XmlPullParser.END_TAG:
if ( tag.equals(TAG_FAMILY) )
{
// add it to the list.
if ( font != null )
{
mFonts.add(font);
font = null;
}
}
else if ( tag.equals(TAG_NAME) )
{
isName = false;
}
else if ( tag.equals(TAG_FILE) )
{
isFile = false;
}
break;
case XmlPullParser.TEXT:
String text = parser.getText();
if ( isName )
{
// value is a name, add it to list of family-names.
if ( font.families != null )
font.families.add(text);
}
else if ( isFile )
{
// value is a file, add it to the proper kind.
FontStyle fontStyle = new FontStyle();
fontStyle.font = Typeface.createFromAsset(context.getAssets(), text);
if ( text.endsWith(STYLE_BOLD) )
fontStyle.style = Typeface.BOLD;
else if ( text.endsWith(STYLE_ITALIC) )
fontStyle.style = Typeface.ITALIC;
else if ( text.endsWith(STYLE_BOLDITALIC) )
fontStyle.style = Typeface.BOLD_ITALIC;
else
fontStyle.style = Typeface.NORMAL;
font.styles.add(fontStyle);
}
}
eventType = parser.next();
}
while ( eventType != XmlPullParser.END_DOCUMENT );
}
catch ( XmlPullParserException e )
{
throw new InflateException("Error inflating font XML", e);
}
catch ( IOException e )
{
throw new InflateException("Error inflating font XML", e);
}
finally
{
if ( parser != null )
parser.close();
}
}
public Typeface get(String family, int style)
{
for ( Font font : mFonts )
{
for ( String familyName : font.families )
{
if ( familyName.equals(family) )
{
// if no style in specified, return normal style.
if ( style == -1 )
style = Typeface.NORMAL;
for ( FontStyle fontStyle : font.styles )
{
if ( fontStyle.style == style )
return fontStyle.font;
}
}
}
}
return null;
}
}
res/values/Fonts.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Fonts">
<!-- using android's -->
<attr name="android:textStyle" />
<!-- our custom attribute -->
<attr name="font" format="string" />
</declare-styleable>
</resources>
res/xml/fonts.xml
<?xml version="1.0" encoding="utf-8"?>
<familyset>
<!-- Arial -->
<family>
<nameset>
<name>Arial</name>
</nameset>
<fileset>
<file>fonts/Arial-Regular.ttf</file>
<file>fonts/Arial-Bold.ttf</file>
<file>fonts/Arial-Italic.ttf</file>
<file>fonts/Arial-BoldItalic.ttf</file>
</fileset>
</family>
</familyset>
Add the fonts inside assets/fonts
Arial-Bold.ttf
Arial-BoldItalic.ttf
Arial-Italic.ttf
Arial-Regular.ttf
Create your custom view Ex: FontableTextView.java
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.widget.TextView;
public class FontableTextView extends TextView
{
private static final String TAG = "FontableTextView";
public FontableTextView(Context context)
{
super(context);
}
public FontableTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
setCustomFont(context, attrs);
}
public FontableTextView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
setCustomFont(context, attrs);
}
/*
* #see android.widget.CompoundButton#onDraw(android.graphics.Canvas)
*/
#Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
}
private void setCustomFont(Context ctx, AttributeSet attrs)
{
// Fonts work as a combination of particular family and the style.
TypedArray a = ctx.obtainStyledAttributes(attrs, R.styleable.Fonts);
String family = a.getString(R.styleable.Fonts_font);
int style = a.getInt(R.styleable.Fonts_android_textStyle, -1);
a.recycle();
// Set the typeface based on the family and the style combination.
if ( family != null )
{
setTypeface(FontManager.getInstance().get(family, style));
}
}
}
Initiate FontManager to set custom fonts at the start of the MainActivity
FontManager.getInstance().initialize(getApplicationContext(), R.xml.fonts);
Use the custom view in Layout XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.package.FontableTextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dip"
android:text="FontableTextView"
android:textStyle="bold"
custom:font="Arial" />
</RelativeLayout>
for actionbar:
use actionbar sherlock (http://actionbarsherlock.com/) and customize its code:
in com.actionbarsherlock.app.Actionbar add these two abstract methods:
public abstract void setTitleTypeface(Typeface TF);
public abstract void setSubtitleTypeface(Typeface TF);
and override these methods in com.actionbarsherlock.internal.app.ActionBarImpl
#Override
public void setTitleTypeface(Typeface TF) {
mActionView.setTitleTypeface(TF); }
#Override
public void setSubtitleTypeface(Typeface TF) {
mActionView.setSubtitleTypeface(TF); }
and also in com.actionbarsherlock.internal.app.ActionBarWrapper like this
#Override
public void setTitleTypeface(Typeface TF) {}
#Override
public void setSubtitleTypeface(Typeface TF) {}
and finally in com.actionbarsherlock.internal.widget.ActionBarView add these methods:
public void setTitleTypeface(Typeface TF){
mTitleView.setTypeface(TF);
}
public void setSubtitleTypeface(Typeface TF){
mSubtitleView.setTypeface(TF);
}
and now use it in your SherlockActivity like this:
Typeface TF = Typeface.createFromAsset(getApplication().getAssets(),
"Arial.ttf");
getSupportActionBar().setTitleTypeface(TF);
Make Sure there is no better way!!!
2. for dialogs, system settings,... u should change code like this!
Related
<android.support.v7.preference.EditTextPreference
android:key="prefTest"
android:title="test number input"
android:inputType="numberDecimal|numberSigned"
android:defaultValue="800"/>
It still shows regular keyboard and allows me to type any character
Is there something wrong with android.support.v7?
android:digits="0123456789"
use this in edittext as it accepts only defined numbers. if its not working then use Android-Support-Preference-V7-Fix library.
Fixed EditTextPreference forwards the XML attributes (like inputType) to the EditText, just like the original preference did.
The Customize your settings section in the developer guide for settings recommends that you set the input type programmatically by using an OnBindEditTextListener as follows:
public class SettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.settings_screen, rootKey);
EditTextPreference weeklyGoalPref = findPreference("weekly_goal");
if (weeklyGoalPref != null) {
weeklyGoalPref.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
}
});
}
}
}
I tried defining the input type as "number" in xml and still got the normal keyboard with letters. This approach worked for me.
I agree that original support preferences has some issues, but for resolving this issue we just need add custom layout and specify EditText with android:inputType="number"
<android.support.v7.preference.EditTextPreference
android:dialogLayout="#layout/preference_dialog_edittext_custom"
So that you may copy original preference_dialog_layout.xml file and edit it.
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="48dp"
android:layout_marginBottom="48dp"
android:overScrollMode="ifContentScrolls">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:orientation="vertical">
<TextView android:id="#android:id/message"
style="?android:attr/textAppearanceSmall"
android:layout_marginBottom="48dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="?android:attr/textColorSecondary" />
<EditText
android:id="#android:id/edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:layout_marginStart="-4dp"
android:layout_marginEnd="-4dp" />
</LinearLayout>
</ScrollView>
android.support.v7.preference.EditTextPreference doesn't contain getEditText() method.
But we can extends android.support.v7.preference.EditTextPreferenceDialogFragmentCompat to set inputType.
public class EditTextPreferenceDialogFragmentCompat extends android.support.v7.preference.EditTextPreferenceDialogFragmentCompat {
private EditText mEditText;
private int mInputType;
public static EditTextPreferenceDialogFragmentCompat newInstance(String key, int inputType) {
EditTextPreferenceDialogFragmentCompat fragment = new EditTextPreferenceDialogFragmentCompat();
Bundle b = new Bundle(2);
b.putString("key", key);
b.putInt("inputType", inputType);
fragment.setArguments(b);
return fragment;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInputType = this.getArguments().getInt("inputType");
}
protected void onBindDialogView(View view) {
this.mEditText = view.findViewById(android.R.id.edit);
mEditText.setInputType(mInputType);
super.onBindDialogView(view);
}
}
Then make your activity implements PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback
Use your EditTextPreferenceDialogFragmentCompat instead of android.support.v7.preference.EditTextPreferenceDialogFragmentCompat
public boolean onPreferenceDisplayDialog(#NonNull PreferenceFragmentCompat preferenceFragmentCompat, Preference preference) {
String key = preference.getKey();
if (/**show your dialog*/) {
EditTextPreferenceDialogFragmentCompat f = EditTextPreferenceDialogFragmentCompat.newInstance(preference.getKey(), InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
f.setTargetFragment(this, 0);
f.show(getFragmentManager(), "android.support.v14.preference.PreferenceFragment.DIALOG");
return true;
}
return false;
}
just use android.support.v7.preference.EditTextPreference in xml
<android.support.v7.preference.PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<android.support.v7.preference.EditTextPreference
.../>
</android.support.v7.preference.PreferenceScreen>
For androidx library i used
val preference = findPreference("pref_key") as EditTextPreference?
preference!!.setOnBindEditTextListener {
editText -> editText.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_SIGNED
}
inside onCreatePreferences function for PreferenceFragmentCompat
Still the same issue in 2021 with AndroidX... I fixed it by copying "EditTextPreference.java" class from the specified link in accepted answer then used it instead of androidx.preference.EditTextPreference on my XML preference screens
package myapp.preferences;
import android.content.Context;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.SparseArrayCompat;
import com.averydennison.containertracking.R;
public class EditTextPreference extends androidx.preference.EditTextPreference {
#Nullable
private OnBindEditTextListener onBindEditTextListener;
private SparseArrayCompat<TypedValue> editTextAttributes = new SparseArrayCompat<>();
private boolean disableMessagePaddingFix;
#SuppressWarnings("unused")
public EditTextPreference(Context context) {
this(context, null);
}
#SuppressWarnings("WeakerAccess")
public EditTextPreference(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.editTextPreferenceStyle);
}
#SuppressWarnings("WeakerAccess")
public EditTextPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
#SuppressWarnings("WeakerAccess")
public EditTextPreference(Context context, final AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
//TypedArray a = getContext().obtainStyledAttributes(
// attrs, R.styleable.EditTextPreference, defStyleAttr, defStyleRes);
//disableMessagePaddingFix = a.getBoolean(R.styleable.EditTextPreference_pref_disableMessagePaddingFix, false);
//a.recycle();
processAttrs(attrs);
super.setOnBindEditTextListener(new OnBindEditTextListener() {
#Override
public void onBindEditText(#NonNull EditText editText) {
if (!disableMessagePaddingFix) {
fixMessagePadding(editText);
}
int n = editTextAttributes.size();
for (int i = 0; i < n; i++) {
int attr = editTextAttributes.keyAt(i);
TypedValue value = editTextAttributes.valueAt(i);
int data = value.data;
// TODO resolve resources?
switch (attr) {
case android.R.attr.inputType:
editText.setInputType(data);
break;
case android.R.attr.textAllCaps:
editText.setAllCaps(data == 1);
break;
case android.R.attr.lines:
editText.setLines(data);
break;
case android.R.attr.minLines:
editText.setMinLines(data);
break;
case android.R.attr.maxLines:
editText.setMaxLines(data);
break;
case android.R.attr.ems:
editText.setEms(data);
break;
case android.R.attr.minEms:
editText.setMinEms(data);
break;
case android.R.attr.maxEms:
editText.setMaxEms(data);
break;
}
}
if (onBindEditTextListener != null) {
onBindEditTextListener.onBindEditText(editText);
}
}
});
}
private void fixMessagePadding(#NonNull View view) {
ViewParent parent = view.getParent();
if (parent instanceof ViewGroup) {
View msgView = ((ViewGroup) parent).findViewById(android.R.id.message);
if (msgView != null) {
ViewGroup.LayoutParams layoutParams = msgView.getLayoutParams();
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;
marginLayoutParams.bottomMargin = 0;
msgView.setLayoutParams(marginLayoutParams);
}
}
}
}
private void processAttrs(AttributeSet attributeSet) {
if (attributeSet == null) {
return;
}
int n = attributeSet.getAttributeCount();
for (int i = 0; i < n; i++) {
int nameRes = attributeSet.getAttributeNameResource(i);
int resId = attributeSet.getAttributeResourceValue(i, 0);
TypedValue value = null;
switch (nameRes) {
case android.R.attr.inputType:
value = new TypedValue();
value.resourceId = resId;
value.data = attributeSet.getAttributeIntValue(i, InputType.TYPE_CLASS_TEXT);
value.type = TypedValue.TYPE_INT_HEX;
break;
case android.R.attr.minEms:
case android.R.attr.maxEms:
case android.R.attr.ems:
case android.R.attr.minLines:
case android.R.attr.maxLines:
case android.R.attr.lines:
value = new TypedValue();
value.resourceId = resId;
value.data = attributeSet.getAttributeIntValue(i, -1);
value.type = TypedValue.TYPE_INT_DEC;
break;
case android.R.attr.textAllCaps:
value = new TypedValue();
value.resourceId = resId;
value.data = attributeSet.getAttributeBooleanValue(i, false) ? 1 : 0;
value.type = TypedValue.TYPE_INT_BOOLEAN;
break;
}
if (value != null) {
editTextAttributes.put(nameRes, value);
}
}
}
/**
* Returns the {#link OnBindEditTextListener} used to configure the {#link EditText}
* displayed in the corresponding dialog view for this preference.
* <p>
* NOTE that this will return the internal {#link OnBindEditTextListener} instead of the one set
* via {#link #setOnBindEditTextListener(OnBindEditTextListener)}.
*
* #return The {#link OnBindEditTextListener} set for this preference, or {#code null} if
* there is no OnBindEditTextListener set
* #see OnBindEditTextListener
*/
#Nullable
//#Override
public OnBindEditTextListener getOnBindEditTextListener() {
return this.onBindEditTextListener;
//return super.getOnBindEditTextListener();
}
#Override
public void setOnBindEditTextListener(#Nullable OnBindEditTextListener onBindEditTextListener) {
this.onBindEditTextListener = onBindEditTextListener;
}
#Deprecated
public EditText getEditText() {
throw new UnsupportedOperationException("Use OnBindEditTextListener to modify the EditText");
}
#Override
public void setText(String text) {
String oldText = getText();
super.setText(text);
if (!TextUtils.equals(text, oldText)) {
notifyChanged();
}
}
}
It happens when using android.support.v14.preference.PreferenceFragment or android.support.v7.preference.PreferenceFragmentCompat even after choosing android:inputType="numberDecimal". This issue could be overcome by using android.preference.PreferenceFragment. Unfortunately, it's deprecated in API level 28.
Even refactoring to AndroidX, using androidx.preference.PreferenceFragment or androidx.preference.PreferenceFragmentCompat didn't fix the issue.
You can retrieve the EditText from the Preference and from there setInputTypes or use KeyListeners to inform the keyboard:
EditText et = (EditText) editTextPref.getEditText();
et.setKeyListener(DigitsKeyListener.getInstance());
found the answer on older thread
Thought I'd add my solution for Android-TV in case someone gets here and needs it.
android_su's reply put me in the right direction, unfortunately, the LeanbackEditTextPreferenceDialogFragmentCompat doesn't support OnPreferenceDisplayDialogCallback.
Instead I had to:
override onCreateView and implement a new newInstance function for LeanbackEditTextPreferenceDialogFragmentCompat using inheritance:
public static class TvPreferencesDialog extends LeanbackEditTextPreferenceDialogFragmentCompat {
public static TvPreferencesDialog newInstance(String key) {
final Bundle args = new Bundle(1);
args.putString(ARG_KEY, key);
final TvPreferencesDialog fragment = new TvPreferencesDialog();
fragment.setArguments(args);
return fragment;
}
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = super.onCreateView(inflater, container, savedInstanceState);
final String key = getArguments().getString(ARG_KEY);
EditText editTextView = root.findViewById(android.R.id.edit);
if (key.equalsIgnoreCase("some pref key 1")) {
editTextView.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
} else if (key.equalsIgnoreCase("some pref key 2")) {
editTextView.setInputType(InputType.TYPE_CLASS_NUMBER);
editTextView.addTextChangedListener(new MyTextWatcher());
}
return root;
}
}
override onPreferenceDisplayDialog inside my LeanbackSettingsFragmentCompat:
#Override
public boolean onPreferenceDisplayDialog(#NonNull PreferenceFragmentCompat caller, Preference pref) {
if (caller == null) {
throw new IllegalArgumentException("Cannot display dialog for preference " + pref + ", Caller must not be null!");
}
final Fragment f;
if (pref instanceof EditTextPreference) {
f = TvPreferencesDialog.newInstance(pref.getKey());
f.setTargetFragment(caller, 0);
startPreferenceFragment(f);
return true;
} else {
return super.onPreferenceDisplayDialog(caller, pref);
}
}
Unfortunately, in androidx.Preference (at least at androidx.preference:preference-ktx:1.1.1) the inputType is not working.
I had to load the xml resource twice:
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.sharedPreferencesName = "alex"
setPreferencesFromResource(R.xml.root_preferences, rootKey)
val xml = resources.getXml(R.xml.root_preferences)
while (xml.eventType != XmlPullParser.END_DOCUMENT) {
xml.parseInputType()
xml.next()
}
}
}
I used a helper extension function:
private fun XmlPullParser.parseInputType(preferenceManager: androidx.preference.PreferenceManager) {
if (eventType == XmlPullParser.START_TAG && name == "EditTextPreference") {
val dictionary = HashMap<String, String>()
for (i in 0 .. attributeCount-1) {
dictionary.put(getAttributeName(i), getAttributeValue(i))
}
val name = dictionary["key"] ?: return
val pref = preferenceManager.findPreference<EditTextPreference>(name) ?: return
val inputType = Integer.decode(attributes["inputType"] ?: "1")
if (inputType != 0) {
pref.setOnBindEditTextListener { editText ->
editText.inputType = inputType
}
}
}
}
EditTextPreference widgets should take the same attributes as a regular EditText, so use:
android:inputType="number"
I want to make my edit box read only but not editable.
User should able to copy from my Edit box but it should not be editable ny user.
please let me know how to do this.
The command text.setTextIsSelectable(true) requires API 11. For those using lower API's use the following XML:
android:inputType="none"
android:textIsSelectable="true"
This will make your editText selectable but not editable.
The easiest way to do this is to add this code:
textInput.setInputType(InputType.TYPE_NULL);
textInput.setTextIsSelectable(true);
textInput.setKeyListener(null);
Create a TextView as has been indicated by the other answer, instead of an EditText. Then override the Activity's context menu in your Activity class as below:
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
menu.add(0, v.getId(), 0, "Copy");
//cast the received View to TextView so that you can get its text
TextView yourTextView = (TextView) v;
//place your TextView's text in the clipboard
ClipboardManager clipboard = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
clipboard.setText(yourTextView.getText());
}
Then simply call registerForContextMenu(yourTextView); in onCreate().
You can overwrite the key listener, so you can do anything except editing
final EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.setOnKeyListener(new OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
return true;
}
});
Use android:editable="false" property for the EditText in your layout view file.
i'm using this class
import android.content.Context;
import android.text.InputFilter;
import android.text.Spanned;
import android.util.AttributeSet;
import android.widget.EditText;
/*
*
* To make EditText read and copy only but not editable
* using
* sendReadOnlyCallback(callback);
*
*/
public class MyEditText extends EditText {
private InputFilter[] originalFilters = null;
private boolean internalChange = false;
private InputFilter[] myInputFilters = null;
private static ReadonlyCallback sDummyCallback = new ReadonlyCallback() {
#Override
public boolean isReadOnly() {
return false;
}
};
private ReadonlyCallback callback = sDummyCallback;
public MyEditText(Context context) {
super(context);
}
public MyEditText(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyEditText(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public interface ReadonlyCallback {
public boolean isReadOnly();
}
public void setReadonlyCallback(ReadonlyCallback cb) {
if (cb == null)
callback = sDummyCallback;
else
callback = cb;
}
public void setFilters(InputFilter[] filters) {
// duplicated from TexView
originalFilters = new InputFilter[filters.length];
System.arraycopy(filters, 0, originalFilters, 0, filters.length);
// funny No. 1 : have to re instantiate `callback`
// otherwise got `NullPointerExcection` when called from `filter`
callback = sDummyCallback;
myInputFilters = new InputFilter[] { new InputFilter() {
// funny No. 2:
// have to make refs to `originalfilters`
// otherwise got `NullPointerExcection` when called from `filter`
InputFilter[] flts = originalFilters;
#Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
if (!internalChange && callback.isReadOnly())
return dest.subSequence(dstart, dend);
int filtercount = flts.length;
if (filtercount == 0)
return null;
// duplicated from InputFilter.AllCaps
for (int i = 0; i < filtercount; i++) {
CharSequence repl = flts[i].filter(source, start, end, dest, start, end);
if (repl != null) {
source = repl;
start = 0;
end = repl.length();
}
if (i == filtercount)
return repl;
}
return null;
}
} };
super.setFilters(myInputFilters);
}
#Override
public InputFilter[] getFilters() {
if (myInputFilters == null)
return super.getFilters();
return originalFilters;
}
#Override
public synchronized void setText(CharSequence text, BufferType type) {
internalChange = true;
super.setText(text, type);
internalChange = false;
}
}
Why not this?
final EditText edittext = (EditText) findViewById(R.id.edittext);
edittext.setEnabled(false);
Is there any library or open source application demo that contains Rich Text Format Edittext component with WYSIWYG interface. I've heard that android-richtexteditor contained such functionality, but it's source code is no longer available.
If anyone have a link or source to the above please share it with me.
Here are two awesome libraries which helped me out. Both of them are implementation of WYSIWYG.
Android RTEditor:
https://github.com/1gravity/Android-RTEditor
RichEditor-Android:
https://github.com/wasabeef/richeditor-android
Their implementation code is also provided.
No there is no library for this but you can do that with using following classes
1.HTML
2.SPANNABLE
3.ForegroundSpan
4.BackgroundSpan
5.AbsoluteSpan
1.http://developer.android.com/reference/android/text/Html.html
using this you can embedd direct html tag with android like bold ,itlic,underlince etc
2.http://developer.android.com/reference/android/text/Spannable.html
(SpannableString ,SpannableStringBuilder, etc)
EDIT
for edit text bold,italic etc.. see some examples on below link
http://www.androidengineer.com/2010/08/easy-method-for-formatting-android.html
https://blog.stylingandroid.com/introduction-to-spans/
Here is the steps to convert an EditText into RichText
1) Create a RichTextEditor class as shown below, this example has support for bold/unbold, you can add more as needed
import android.app.Activity;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.TextWatcher;
import android.text.style.StyleSpan;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import com.loa.learnandcheck.R;
import com.loa.learnandcheck.util.ResourceHelper;
public class RichTextEditor implements ImageButton.OnClickListener, TextWatcher {
private boolean textBold;
private ImageButton buttonBold;
private EditText editText;
private Activity parent;
private int styleStart = 0;
public RichTextEditor(Activity parent, EditText editText){
try {
this.parent = parent;
this.editText = editText;
init();
}catch (Exception e) {
e.printStackTrace();
}
}
public void init(){
try {
buttonBold = (ImageButton)parent.findViewById(R.id.text_control_text_bold);
if(buttonBold!=null) {
buttonBold.setOnClickListener(this);
}
editText.addTextChangedListener(this);
}catch (Exception e) {
e.printStackTrace();
}
}
public Activity getParent() {
return parent;
}
public void setParent(Activity parent) {
this.parent = parent;
}
public void updateBackground(boolean itemSelected, ImageButton button) {
try {
if(itemSelected) {
button.setBackgroundColor(ResourceHelper.getThemeColor(parent,R.color.colorGray, Color.GRAY));
} else {
button.setBackgroundColor(ResourceHelper.getThemeColor(parent,R.color.colorWhite, Color.WHITE));
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void handleBoldButtonClick() {
try {
textBold = !textBold;
updateBackground(textBold,buttonBold);
int selectionStart = editText.getSelectionStart();
int selectionEnd = editText.getSelectionEnd();
if (selectionStart > selectionEnd){
int temp = selectionEnd;
selectionEnd = selectionStart;
selectionStart = temp;
}
if (selectionEnd > selectionStart) {
Spannable str = editText.getText();
StyleSpan[] ss = str.getSpans(selectionStart, selectionEnd, StyleSpan.class);
boolean exists = false;
for (int i = 0; i < ss.length; i++) {
if (ss[i].getStyle() == android.graphics.Typeface.BOLD){
str.removeSpan(ss[i]);
exists = true;
}
}
if (!exists){
str.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), selectionStart, selectionEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void handleFormat(Editable s, int position, int format) {
try {
StyleSpan[] ss = s.getSpans(styleStart, position, StyleSpan.class);
for (int i = 0; i < ss.length; i++) {
if (ss[i].getStyle() == format){
s.removeSpan(ss[i]);
}
}
s.setSpan(new StyleSpan(format), styleStart, position, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onClick(View view) {
try {
switch (view.getId()) {
case R.id.text_control_text_bold:
handleBoldButtonClick();
break;
//more formats to be handled as needed here...
default:
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void afterTextChanged(Editable s) {
int position = Selection.getSelectionStart(editText.getText());
//handle bold
if (textBold){
handleFormat(s, position, android.graphics.Typeface.BOLD);
}
//more formats to be handled as needed here...
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
styleStart = start;
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
//unused
}
}
2) Create the following ResourceHelper class
public class ResourceHelper {
/**
* Get a color value from a theme attribute.
* #param context used for getting the color.
* #param attribute theme attribute.
* #param defaultColor default to use.
* #return color value
*/
public static int getThemeColor(Context context, int attribute, int defaultColor) {
int themeColor = 0;
String packageName = context.getPackageName();
try {
Context packageContext = context.createPackageContext(packageName, 0);
ApplicationInfo applicationInfo =
context.getPackageManager().getApplicationInfo(packageName, 0);
packageContext.setTheme(applicationInfo.theme);
Resources.Theme theme = packageContext.getTheme();
TypedArray ta = theme.obtainStyledAttributes(new int[] {attribute});
themeColor = ta.getColor(0, defaultColor);
ta.recycle();
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return themeColor;
}
}
3) Create layout with an edittext and control buttons(ImageButtons) as shown below
<EditText
android:id="#+id/text_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="5"
android:inputType="textMultiLine"
android:lines="5"
android:scrollbars="vertical"
android:background="#color/colorWhite"
android:hint="#string/text_content" />
<ImageButton
android:id="#+id/text_control_text_bold"
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#color/colorWhite"
android:src="#drawable/ic_action_text_bold"/>
4) In Activity, load the edittext and create RichTextEditor instance as show below
inputText = (EditText)findViewById(R.id.text_content) ;
new RichTextEditor(this,inputText);
Is it possible to use somehow Typeface font definition loaded from assets with EditText in widget ?
The font you want to use needs to reside in the assets/fonts directory, and you access it like so:
Typeface myFont = Typeface.createFromAsset(getAssets(), "fonts/myfont.ttf");
edittext.setTypeface(myFont);
editText.setTypeface(Typeface.createFromAsset(context.getAssets(),"fonts/myfont.ttf"));
Assuming you have this structure of files:
/assets/fonts/myfont.ttf
Please See below code for that, it will solve your problem.
// text view label
TextView mTextView1 = (TextView) findViewById(R.id.TextView1);
// Loading Font Face
Typeface tf = Typeface.createFromAsset(getAssets(), "DroidSansFallback.ttf");
// Applying font
mTextView1.setTypeface(tf);
And see below link for more information.
Android Development – Customize Android Fonts
Typeface tf = Typeface.createFromAsset(getAssets(),"fonts/Comic.ttf");
youredittext.setTypeface(tf);
I have tried this now. It worked for me. Good luck
Other betther form to implement this and avoid to add the font to all the textviews is extends a TextView (or EditText or ... ) and apply the font on the setTypeface method. With this method you can control bold, italic and other styles.
Here is a code for a class that extends TextView and apply a Roboto font. Moreover it controls some bugs that Android 4.0 has with the html codes when set an Spannable from an HTML
public class TextViewRoboto extends TextView {
public static final String TAG = "TextViewRoboto";
public TextViewRoboto(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public TextViewRoboto(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TextViewRoboto(Context context) {
super(context);
}
#Override
public void setTypeface(Typeface tf, int style) {
//This is to override eclipse error messages
if (!super.isInEditMode()) {
if (style == Typeface.BOLD)
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Bold.ttf"));
else if (style == Typeface.ITALIC)
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Italic.ttf"));
else
super.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fonts/Roboto-Regular.ttf"));
}
}
//
// With this code aboid the <b> and <strong> problem on Jelly Bean
//
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
try{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}catch (ArrayIndexOutOfBoundsException e){
//Logger.w(TAG, "Problem onMeasure. Set normal text");
setText(getText().toString());
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
#Override
public void setGravity(int gravity){
try{
super.setGravity(gravity);
}catch (ArrayIndexOutOfBoundsException e){
//Logger.w(TAG, "Problem setGravity. Set normal text");
setText(getText().toString());
super.setGravity(gravity);
}
}
#Override
public void setText(CharSequence text, BufferType type) {
try{
super.setText(text, type);
}catch (ArrayIndexOutOfBoundsException e){
//Logger.w(TAG, "Problem on setText. Set normal text");
setText(text.toString());
}
}
public void setHTMLText(CharSequence text, BufferType type) {
String tmpText = text.toString();
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
tmpText = tmpText.replace("<strong>", "<b>");
tmpText = tmpText.replace("</strong>", "</b>");
tmpText = tmpText.replace("<em>", "<i>");
tmpText = tmpText.replace("</em>", "</i>");
text = tmpText;
}
try{
super.setText(Html.fromHtml(tmpText), type);
}catch (ArrayIndexOutOfBoundsException e){
//Logger.w(TAG, "Problem on setText. Set normal text");
setText(text.toString());
}
}
}
You can use this
editText.setTypeface(Typeface.SERIF);
I was wondering if it is possible to abbreviate only a portion of a string in a TextView. What I would like to do is something like this:
Element with short title (X)
Element with a very lo...(X)
The title should be ellipsized, but the X must be always visible. In my case, is not possible to use more than one TextView. Do you think there is a simple way of doing this?
Thanks!
I really needed a clean solution for a project so after searching around and not finding any solutions I felt I liked, I took some time to write this up.
Here is an implementation of a TextView with enhanced ellipsis control. The way it works is by using Android's Spanned interface. It defines an enum you can use to tag the specific section of text you'd like to be ellipsized if needed.
Limitations:
Does not support ellipsis at MIDDLE. This should be easy to add if it's really needed (I didn't).
This class will always render the text onto one line, as it only supports a single line of text. Others are welcome to extend it if that's needed (but it's a far harder problem).
Here's a sample of the usage:
FooActivity.java
class FooActivity extends Activity {
/**
* You can do this however you'd like, this example uses this simple
* helper function to create a text span tagged for ellipsizing
*/
CharSequence ellipsizeText(String text) {
SpannableString s = new SpannableString(text);
s.setSpan(TrimmedTextView.EllipsizeRange.ELLIPSIS_AT_END, 0, s.length(),
Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
return s;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.foo_layout);
TextView textView = (TextView) findViewById(R.id.textView4);
SpannableStringBuilder text = new SpannableStringBuilder();
text.append(ellipsizeText("This is a long string of text which has important information "));
text.append("AT THE END");
textView.setText(text);
}
}
res/layouts/foo_layout.xml
<com.example.text.TrimmedTextView
android:id="#+id/textView4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"/>
That's it
Here's an example of the result:
The Implementation
package com.example.text;
import android.content.Context;
import android.text.Editable;
import android.text.Layout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextUtils.TruncateAt;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;
public class TrimmedTextView extends TextView {
public static enum EllipsizeRange {
ELLIPSIS_AT_START, ELLIPSIS_AT_END;
}
private CharSequence originalText;
private SpannableStringBuilder builder = new SpannableStringBuilder();
/**
* This allows the cached value of the original unmodified text to be
* invalidated whenever set externally.
*/
private final TextWatcher textCacheInvalidator = new TextWatcher() {
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
originalText = null;
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void afterTextChanged(Editable s) {
}
};
public TrimmedTextView(Context context) {
this(context, null, 0);
}
public TrimmedTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TrimmedTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
addTextChangedListener(textCacheInvalidator);
Log.v("TEXT", "Set!");
}
/**
* Make sure we return the original unmodified text value if it's been
* custom-ellipsized by us.
*/
public CharSequence getText() {
if (originalText == null) {
return super.getText();
}
return originalText;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Layout layout = getLayout();
CharSequence text = layout.getText();
if (text instanceof Spanned) {
Spanned spanned = (Spanned) text;
int ellipsisStart;
int ellipsisEnd;
TruncateAt where = null;
ellipsisStart = spanned.getSpanStart(EllipsizeRange.ELLIPSIS_AT_START);
if (ellipsisStart >= 0) {
where = TruncateAt.START;
ellipsisEnd = spanned.getSpanEnd(EllipsizeRange.ELLIPSIS_AT_START);
} else {
ellipsisStart = spanned.getSpanStart(EllipsizeRange.ELLIPSIS_AT_END);
if (ellipsisStart >= 0) {
where = TruncateAt.END;
ellipsisEnd = spanned.getSpanEnd(EllipsizeRange.ELLIPSIS_AT_END);
} else {
// No EllipsisRange spans in this text
return;
}
}
Log.v("TEXT", "ellipsisStart: " + ellipsisStart);
Log.v("TEXT", "ellipsisEnd: " + ellipsisEnd);
Log.v("TEXT", "where: " + where);
builder.clear();
builder.append(text, 0, ellipsisStart).append(text, ellipsisEnd, text.length());
float consumed = Layout.getDesiredWidth(builder, layout.getPaint());
CharSequence ellipsisText = text.subSequence(ellipsisStart, ellipsisEnd);
CharSequence ellipsizedText = TextUtils.ellipsize(ellipsisText, layout.getPaint(),
layout.getWidth() - consumed, where);
if (ellipsizedText.length() < ellipsisText.length()) {
builder.clear();
builder.append(text, 0, ellipsisStart).append(ellipsizedText)
.append(text, ellipsisEnd, text.length());
setText(builder);
originalText = text;
requestLayout();
invalidate();
}
}
}
}
You can try using something like this:
myTextView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
It might not give you exactly what you want though, it may do something like this:
Element wi...title (X)
Reference Info
TruncateAt
setEllipsize