I want to have a portion of my TextView invisible. In detail, I present a math problem to the user:
9 * 9 = 81
and I want 81 to be invisible. As user types correct answer, I make digit "8" and then "1" visible.
I tried to use TextAppearanceSpan and ForegroundColorSpan with transparent color (both #00000000 and Color.TRANSPARENT) and they work perfectly for every device and emulator except KindleFire device and emulator.
On Kindle Fire, "81" appears colored in sort-of-dark-grey. It seems that rasterizer tries to make it invisible against some "sort-of-dark-grey" background, not against background (which looks like grid paper image) that I've set in the root LinearLayout of my Activity.
My question is: how can I make a portion of text in TextView invisible using neither TextAppearanceSpan nor ForegroundColorSpan? Does there exist another "span" that measures text correctly, but does not paint it?
Update
I've discovered that there exist some mysterous RasterizerSpan and MetricAffectingSpan, which could (judging by the title) help.
As I can see, the only meaning of RasterizerSpan is to set a Rasterizer to the TextPaint object:
public void updateDrawState(TextPaint ds) {
ds.setRasterizer(mRasterizer);
}
I found it promising: if I were able to set a kind of "void" rasterizer (that just does nothing), it would make this text invisible. Unfortunately
new RasterizerSpan(null); // (set mRasterizer to null)
did not help.
My another idea is to implement a custom ShaderSpan that would set a "void" shader:
public void updateDrawState(TextPaint ds) {
ds.setShader(myCustomVoidShader);
}
but I do not understand how to create a shader that produces "nothing".
See if overriding updateDrawState() on your ForegroundColorSpan and calling setXferMode() will work:
public class TransparentSpan extends ForegroundColorSpan {
private final PorterDuffXfermode MODE = new PorterDuffXfermode(PorterDuff.Mode.DST);
public TransparentSpan(int color) {
super(color);
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setXfermode(MODE);
}
}
Sorry, I didn't have a Kindle Fire to test with :)
You can use AbsoluteSizeSpan, set the size to 0. So it will invisible
span = new AbsoluteSizeSpan(0, true);
spannableString.setSpan(span, wordPosition.start, wordPosition.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
Notice:
The next word of the invisible word will take place the invisible word position.
Why not using the android visibility (true or false). It will do the same job you need (or there is a specificreason you would lie to use Span) ?
Related
I have a problem with striking through a part of text that is displayed in the button.
I'm trying to achieve the effect using SpannableString and StrikethroughSpan. I have the following method:
public static SpannableString strikethrough(SpannableString text) {
StrikethroughSpan span = new StrikethroughSpan();
text.setSpan(span, 0, text.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return text;
}
Then I do something like this
SpannableString strikethoughPart = new SpannableString("striked_part");
TextStyleHelper.strikethrough(strikethoughPart);
final CharSequence concatted = TextUtils.concat("not striked ", strikethoughPart);
justButton.setText(concatted);
justText.setText(concatted);
The TextView is displayed correctly, with one part seen as striked. However, the button is displayed not correctly, there is no strikethrough effect (the same on all apis from 21 to 25)
api 21 image.
API 26+ works as expected api 26 image.
How can I strikethrough only part of the button text on lower apis (21-25)? I can achieve the effect of striking through with setPaintFlags method but that will strike through all text and I don't need that.
Tried classes of button: usual Button and MaterialButton.
I am using EditText's to accept an OTP, where user has focus on next EditText once he enters a digit to a field and so. It works fine on all devices. But on devices running android OS P i.e. API 28, requestFocus() does not work, and user is not able to enter digits to consecutive EditTexts as focus doesn't move automatically.
Here is the code - by default all EditText's are disable to prevent from opening system keyboard. I am using my own CustomKeybaord to accept numbers. However it works except Android P.
mEtCode1.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
Log.d("BEFORE_", charSequence.toString());
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
hideError(charSequence.toString());
if (!charSequence.toString().isEmpty()) {
mEtCode2.requestFocus();
mEtCode1.setBackground(getResources().getDrawable(R.drawable.verify_code_edit_text_background));
mEtCode2.setBackground(getResources().getDrawable(R.drawable.verify_code_edit_text_background));
mEtCode1.setEnabled(false);
}
}
#Override
public void afterTextChanged(Editable editable) {
}
});
Please help me with this
Thank you, in advance
I had the same issue with my OTP screen on devices with Android P sdk. The problem was that i set the height and width of the editText to 0dp, which is focus disabling in android P,
as described in Android Developer page in the Android P change log:
android-9.0-changes-28#ui-changes
Views with 0 area (either a width or a height is 0) are no longer focusable.
This is issue with Android P. And what worked for me is the following code block, So sharing here:
enterOtpTextFrame.postDelayed(Runnable {
enterOtpTextFrame.requestFocus()
}, 100
)
we require to call requestFocus with postDelayed with some small time amount. In my case it is 100 millisecond.
Here is the official documentation for requestFocus method. It states there that it only works if the desired view for which you want to have focus is enabled, has size, is visible, is focusable and is FocusableInTouchMode.
I had exact same issue. I was using databinding to set the enable state of my EditText. I realised that requestFocus was not working because databinding, due to some unknown reasons, was not enabling my textview in time.
Here is my code:
/*
setMyEditTextEnabled is my method to which my view is binded i.e.
android:enabled="#{vm.myEditTextEnabled, default=false}"
This worked for all version except Android P because it has
some timing issues with API 28 (not sure what)
*/
//binding.getVm().setMyEditTextEnabled(true);
/*
So to make it work, I am enabling my EditText directly and
it works for all versions.
*/
binding.myEditText.setEnabled(true);
binding.myEditText.requestFocus();
Also, as mentioned in following post: EditText requestFocus not working
Do set focusable and focusableInTouchMode to true as well.
In short, my point is to make sure that your edit text is fulfilling all requirements as mentioned in official doc in order to requestFocus to work.
Encountered a similar problem when popping an alert dialog. In my case, postDelayed'ing a focus request or forcing the soft keyboard to pop up didn't work. Even if I could manage to pop up the keyboard, the focus stayed on an EditText in the main activity; needless to say I have tried clearing its focus and even disabling it.
However, popping the alertDialog delayed did the trick:
final AlertDialog alertDialog = alertDialogBuilder.create(); //a builder of your own
final Runnable r = new Runnable() {
public void run() {
alertDialog.show();
}
};
editTextOnMainActivity.postDelayed(r, 100);
I have a problem statement where i need to run my application with Accessibility setting on, to have talk back feedback, but the problem here is when i click on a TextView which have Spannable link in it, then it reads the full text but dose not allow me to click on that Spannable text separately while disabling the accessibility allows to make string multi spannable or link clickable.
here is my code to make String clickable :
SpannableString ss = new SpannableString("Android is a Software stack");
ClickableSpan clickableSpan = new ClickableSpan() {
#Override
public void onClick(View textView) {
startActivity(new Intent(MyActivity.this, NextActivity.class));
}
#Override
public void updateDrawState(TextPaint ds) {
super.updateDrawState(ds);
ds.setUnderlineText(false);
}
};
ss.setSpan(clickableSpan, 22, 27, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
TextView textView = (TextView) findViewById(R.id.hello);
textView.setText(ss);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setHighlightColor(Color.TRANSPARENT);
If you are using Android X library you should be able to handle accessibility and clickable spannable strings by:
ViewCompat.enableAccessibleClickableSpanSupport(yourView);
Also make sure you have the latest dependency:
com.android.support:appcompat-v7:28.0.0
It should work back to API 19.
Note: To enable Android X library go to your gradle.properties and add these lines:
android.useAndroidX = true
android.enableJetifier = true
I'm afraid there is no way in android to implement that (I had the same issue for months). the only way is using the local context menu. Looks like Talkback is trying to make the ADA users to get use to the menus using there gestures, which will fix too many issue in our dev side. There might be another way, which is creating a WebView and then add html elements which will handle everything, BUT this will be bad for the app performance :(
As mentioned here: Clickable links (Google support)
you have to access local context menu to activate any clickable span by Swiping up and then right, and then click on Links submenu.
Hope this helps :)
Try this one, worked for me. An alternate working solution.
private void setUpBottomSheetAccessibility() {
ViewCompat.setAccessibilityDelegate(view, new AccessibilityDelegateCompat() {
#Override
public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_LONG_CLICKED) {
//Put your work to be done on double click;
}
super.onPopulateAccessibilityEvent(host, event);
}
});
}
Above code view is your Textview or any view. And this event work on double click.
Working fine at my end.
Nothing to do.Just you click the Spannable link with two finger on the screen, and one of them must be on the Spannable link. Try some times!!!
I'd like to gray out a button so it appears disabled to the user, but still listen for clicks so that I can display a message to the user that explains why the button isn't applicable.
I'd like to ensure that the Android API is the one configuring whatever is the appropriate standard disabled appearance as opposed to manually setting the button color to gray, etc. What's the best way to do this?
Related: Android - Listen to a disabled button
this is custom button which expose the event of touch when disabled
it working for sure, and tested. designed specific to you
public class MyObservableButton extends Button
{
public MyObservableButton(Context context, AttributeSet attrs)
{
super(context, attrs);
}
private IOnClickWhenEnabledListner mListner;
public void setOnClickWhenEnabledListener(IOnClickWhenEnabledListner listener) {
mListner = listener;
}
private interface IOnClickWhenEnabledListner {
public void onClickWhenEnabled();
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (!isEnabled() && mListner != null) {
mListner.onClickWhenEnabled();
}
}
return super.onTouchEvent(event);
}
}
this is the right way to accomplish what you want from my point of view as android developer.
there is no problem extanding all android's views, and use them on the xml files, and source instead..
good luck
You could also manually set the background of your Button to the default one for disabled. But leave the button enabled and handle the click events in the normal fashion
something like this should do it:
mBtn.setBackgroundResource(android.R.drawable.btn_default_normal_disabled);
I am not an Android expert, so there could be better ways, but what about disabling the button and overlaying a transparent view that will catch the events?
You could have the view always there laying below the button so you just need to change a z-index, or create it dynamically when needed.
If your button is on the newer types that controls color via backgroundTint rather then background, this is what you should do:
if (enabled) {
ViewCompat.setBackgroundTintList(btn, getResources().getColorStateList(R.color.button_states)); // either use a single color, or a state_list color resource
} else {
ViewCompat.setBackgroundTintList(btn, ColorStateList.valueOf(Color.GRAY));
}
// make sure we're always clickable
btn.setEnabled(true);
btn.setClickable(true);
You could also set the Button's style to look grayed out (for both pressed and non-pressed states), then setOnClickListener() as normal, but have the onClick() method give the message that it isn't clickable.
Since button extends textview. You may use the methods in textview such as .setTextColor() or .setBackgroundColor() .
Now for the the display you have 2 options:
AlertDialog - displays an alert but doesn't self close unless specified.
Toast - displays a text over a given time and self closes.
take your pick.
I'm trying to get Android to select all the text in an EditText field when it gets the focus. I'm using this attribute in the layout (on both fields):
android:selectAllOnFocus="true"
I'm not sure if this is relevant, but to get the cursor to the first editable field (there's also a disabled field before it), I'm using the following commands:
quizStartNum.setFocusable(true);
quizStartNum.requestFocus();
But, while the cursor does move to the desired field when the layout is first displayed, the text doesn't get highlighted; instead the cursor ends up to the left of the text, the default behavior. If I move to the second field by touching it, all the text is selected as desired. Then, if I move back to the first field, again by touching it, the text is also completely selected. I would like to have the behavior right from the start. Is there a way to do this?
If android:selectAllOnFocus="true" does not work, try calling setSelectAllOnFocus(true) on that particular EditText.
If that doesn't work either, this is another workaround from a previous SO post.
EditText dummy = ...
dummy.setOnFocusChangedListener(new OnFocusChangedListener(){
public void onFocusChange(View v, boolean hasFocus){
if (hasFocus) && (isDummyText())
((EditText)v).selectAll();
}
});
I had a similar issue and android:selectAllOnFocus="true" did not work for me.
The reason was that i was programatically requesting focus to the EditText before it was displayed. So if you are doing this for a EditText in an AlertDialog make sure you show it before you request focus to the EditText.
EditText should be focussed after it displayed.
Following workout worked for me,
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set Input Methode
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
#Override
public void onStart() {
super.onStart();
new Handler().post(new Runnable() {
#Override
public void run() {
Dialog dialog = getDialog();
if (dialog != null) {
// Set Layout
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
// Set Cancelable False
setCancelable(false);
// Set Focus Here <------------------------
uiET_myTextView.requestFocus();
}
}
});
}
Try removing your focus commands. They aren't necessary, Android should focus on the first field automatically?
I also noticed that with android:selectAllOnFocus="true" seemed not to work, I used the mouse to select EditText in the emulator, but if I used my finger and touched it, as if on the phone, it worked. If you don't have a touch screen on your computer you may have to install your app on a physical device to test it.
Android Studio may not recognize the mouse in this case
I'll refer to this older post.
If you just want your EditText to show a hint (for "what goes in here"), you might want to use the Android's XML-attribute hint (link).