Is there any way to programatically select text in a TextView? - android

I have a TextView that I'm looking to allow the user to search in for a specific string. If the string is found, it should highlight. Using a background span is too slow and awkward, so I am trying to figure out if I can just have it select the string. I know with EditText this would be possible using setSelection(), but I don't want the user to be able to edit the text, while still being able to manually highlight text, which I can't seem to do manage with an EditText.
I guess, then it's an either or; is it either possible to programmatically select text in a TextView or possible to allow text selection without allowing editing in an EditText?
Note: I'm actually using a custom view extending TextView, so I'm assuming it's either that or extend EditText; I'm just not sure which (if either) will work.

Not sure whether the question is still actual, I will provide my solution. Maybe will be useful for people coming from search engines.
So the purpose, as I understood, is to select all text in TextView without being able to modify its content. I didn't check how effective it is against very large text, but hope that not so bad.
Please note, API version should be >=11
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;
public class SelectableTextView extends TextView
{
public SelectableTextView(Context context)
{
super(context);
init();
}
public SelectableTextView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr)
{
super(context, attrs, defStyleAttr);
init();
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init()
{
if (Build.VERSION.SDK_INT > 10)
setTextIsSelectable(true);
}
#Override
public boolean onTextContextMenuItem(int id)
{
switch (id)
{
case android.R.id.cut:
return true;
case android.R.id.paste:
return true;
case android.R.id.shareText:
{
String selectedText = getText().toString().substring(getSelectionStart(), getSelectionEnd());
if (selectedText != null && !selectedText.isEmpty())
{
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, selectedText);
sendIntent.setType("text/plain");
sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(sendIntent);
}
return true;
}
case android.R.id.selectAll:
{
selectAllText();
return true;
}
}
return super.onTextContextMenuItem(id);
}
public void selectAllText()
{
if (Build.VERSION.SDK_INT > 10)
Selection.setSelection((Spannable) getText(), 0, length());
}
}

Related

Hide a Preference-item depending on the state (enabled/disabled) of another Preference in PreferenceScreen

I'm creating a settings screen, and I have a few settings items:
SwitchPreferenceCompat and my CustomPreference.
I need the СustomPreference to disappear(hide) when the SwitchPreferenceCompat is turned off and appear(show) when the SwitchPreferenceCompat is turned on.
Out of the box, only the "dependency" mechanism is available by specifying the "dependency" attribute for some Preferences, which only disables/enables items, and I need to change visibility.
Is there a way to achieve this?
create customPreference and override onDependencyChanged().
package com.paul.ttcapp.p9988030.helper.ui;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.EditTextPreference;
import androidx.preference.Preference;
public class PaulEditTextPreference extends EditTextPreference {
public PaulEditTextPreference(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public PaulEditTextPreference(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public PaulEditTextPreference(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public PaulEditTextPreference(#NonNull Context context) {
super(context);
}
#Override
public void onDependencyChanged(#NonNull Preference dependency, boolean disableDependent) {
// If the corresponding dependency is disabled, disable (hide) this setting as well.
setVisible(!disableDependent);
super.onDependencyChanged(dependency, disableDependent);
}
}

Clickable days from a List of days

Hi all I have a question ,if someone can help me implement this design or give me a path to look from.
Actually i want to implement this UI , a user can select one ore more days ,when he selecte a day the fond of the day become bold when he unselect the day the style of the day become normal like Saturday in our case
i tried to implement this UI using toogle button but unfortunately i failed can anyone help me achieve this goal
thank you all for your help
You could have something like this if you are using multiple TextView's in something like a LinearLayout.
public class BoldTextView extends TextView implements View.OnClickListener {
private boolean bold = false;
public BoldTextView(Context context) {
this(context, null);
}
public BoldTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BoldTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOnClickListener(this);
}
#Override
public void onClick(View v) {
if (bold) {
bold = false;
setTypeface(null, Typeface.NORMAL);
} else {
bold = true;
setTypeface(null, Typeface.BOLD);
}
}
public boolean isBold() {
return bold;
}
}

Android Ripple Effect for my custom button

I have created a project with custom button class as below.
package app.kibbeh.widget;
import android.content.Context;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Button;
public class MyFontButton extends Button {
private static final String TAG = "TextView";
private Typeface typeface;
public MyFontButton(Context context) {
super(context);
}
public MyFontButton(Context context, AttributeSet attrs) {
super(context, attrs);
setCustomFont(context, "");
}
public MyFontButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setCustomFont(context, "");
}
private boolean setCustomFont(Context ctx, String asset) {
try {
if (this.typeface == null) {
Log.i(TAG, "asset:: fonts/" + asset);
this.typeface = Typeface.createFromAsset(ctx.getAssets(), "fonts/avenirroman.ttf");
}
setTypeface(this.typeface);
return true;
} catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "Could not get typeface: " + e.getMessage());
return false;
}
}
}
Now i have to add ripple effect from here. so is it possible or i have to add rippelview in all xml file ? please guide me.
Thank you..
try this link for set the ripple effect on button:
Material effect on button with background color
Android L's Ripple Effect - Touch Feedback for Buttons - Using XML

VisibilityAwareImageButton Usage

I was recently working with ImageButtons and I came across this new type of ImageButton 'VisibilityAwareImageButton'. It would be really helpful if someone could tell me the usage of this ImageButton and how is it different from the regular ImageButton? Thanks in advance :)
Here's the full source for VisibilityAwareImageButton.
class VisibilityAwareImageButton extends ImageButton {
private int mUserSetVisibility;
public VisibilityAwareImageButton(Context context) {
this(context, null);
}
public VisibilityAwareImageButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VisibilityAwareImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mUserSetVisibility = getVisibility();
}
#Override
public void setVisibility(int visibility) {
internalSetVisibility(visibility, true);
}
final void internalSetVisibility(int visibility, boolean fromUser) {
super.setVisibility(visibility);
if (fromUser) {
mUserSetVisibility = visibility;
}
}
final int getUserSetVisibility() {
return mUserSetVisibility;
}
}
It appears to be almost exactly the same as a regular ImageButton, only it keeps track of the last visibility actually set by the user. The only usage I can find is in the FloatingActionButton source. It is used to keep track of what the user wants the visibility of the view to be while it does it's own internal changes and animations. i.e.
if (child.getUserSetVisibility() != VISIBLE) {
// The view isn't set to be visible so skip changing it's visibility
return false;
}
It's in the design support library and has package visibility, so it seems like Google intends on using it internally (and seemingly only for the FAB implementation at this time).

Custom TextView - setText() called before constructor

I've got a problem with my CustomTextView. I'm trying to get a custom value from my layout-xml file and use this in my setText() method. Unfortunately the setText() method gets called before the constructor and because of this I can't use the custom value in this method.
Here's my code (broken down to the relevant parts):
CustomTextView.class
public class CustomTextView extends TextView {
private float mHeight;
private final String TAG = "CustomTextView";
private static final Spannable.Factory spannableFactory = Spannable.Factory.getInstance();
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "in CustomTextView constructor");
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
this.mHeight = values.getDimension(R.styleable.CustomTextView_cHeight, 20);
}
#Override
public void setText(CharSequence text, BufferType type) {
Log.d(TAG, "in setText function");
Spannable s = getCustomSpannableString(getContext(), text);
super.setText(s, BufferType.SPANNABLE);
}
private static Spannable getCustomSpannableString(Context context, CharSequence text) {
Spannable spannable = spannableFactory.newSpannable(text);
doSomeFancyStuff(context, spannable);
return spannable;
}
private static void doSomeFancyStuff(Context context, Spannable spannable) {
/*Here I'm trying to access the mHeight attribute.
Unfortunately it's 0 though I set it to 24 in my layout
and it's correctly set in the constructor*/
}
}
styles.xml
<declare-styleable name="CustomTextView">
<attr name="cHeight" format="dimension"/>
</declare-styleable>
layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ctvi="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.mypackage.views.CustomTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="#string/my_fancy_string"
android:textSize="16sp"
ctvi:cHeight="24dp" />
</LinearLayout>
And just as a proof - here's the LogCat output:
30912-30912/com.mypackage.views D/CustomTextView﹕ in setText function
30912-30912/com.mypackage.views D/CustomTextView﹕ in CustomTextView constructor
So as you can see the setText() method is called before the constructor. That's kinda weird and I don't know what I need to change in order to use my custom attribute (cHeight) in the setText-method.
Thanks in advance for any help!
It's the TextView super() constructor that calls your setText() based on the attribute values.
If you really need to access your custom attribute when setting a text value, use a custom attribute for the text as well.
I don't think any of this solutions are good, IMHO. What if you just use a custom method, like setCustomText() instead of overriding the custom TextView.setText(). I think it could be much better in terms of scalability, and hacking / overriding the implementation of the TextView could lead you into future problems.
Cheers!
First of all, remember to always recycle the TypedArray after using it.
TextView calls #setText(CharSequence text, BufferType type) during its construction therefore define a delayed call to setText as so:
private Runnable mDelayedSetter;
private boolean mConstructorCallDone;
public CustomTextView(Context context, AttributeSet attrs) {
super(context, attrs);
Log.d(TAG, "in CustomTextView constructor");
TypedArray values = context.obtainStyledAttributes(attrs, R.styleable.CustomTextView);
this.mHeight = values.getDimension(R.styleable.CustomTextView_cHeight, 20);
mConstructorCallDone = true;
}
Then inside your setText-override:
public void setText(final CharSequence text, final TextView.BufferType type) {
if (!mConstructorCallDone) {
// The original call needs to be made at this point otherwise an exception will be thrown in BoringLayout if text contains \n or some other characters.
super.setText(text, type);
// Postponing setting text via XML until the constructor has finished calling
mDelayedSetter = new Runnable() {
#Override
public void run() {
CustomTextView.this.setText(text, type);
}
};
post(mDelayedSetter);
} else {
removeCallbacks(mDelayedSetter);
Spannable s = getCustomSpannableString(getContext(), text);
super.setText(s, BufferType.SPANNABLE);
}
}
Unfortunately it is a limitation on Java, that requires to call super(..) in constructor before anything else. So, your only workaround is to call setText(..) again after you initialize the custom attributes.
Just remember, as setText called also before you initialize your custom attributes, they may have null value and you can get NullPointerException
Check my example of customTextView which capitalize first letter and adds double dots at the and (I use it in all my activities)
package com.example.myapp_android_box_detector;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.widget.AppCompatTextView;
import android.util.AttributeSet;
public class CapsTextView extends AppCompatTextView {
public Boolean doubleDot;
private Boolean inCustomText = false;
public CapsTextView(Context context){
super(context);
doubleDot = false;
setText(getText());
}
public CapsTextView(Context context, AttributeSet attrs){
super(context, attrs);
initAttrs(context, attrs);
setText(getText());
}
public CapsTextView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
initAttrs(context, attrs);
setText(getText());
}
public void initAttrs(Context context, AttributeSet attrs){
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CapsTextView, 0, 0);
doubleDot = a.getBoolean(R.styleable.CapsTextView_doubleDot, false);
a.recycle();
}
#Override
public void setText(CharSequence text, BufferType type) {
if (text.length() > 0){
text = String.valueOf(text.charAt(0)).toUpperCase() + text.subSequence(1, text.length());
// Adds double dot (:) to the end of the string
if (doubleDot != null && doubleDot){
text = text + ":";
}
}
super.setText(text, type);
}
}

Categories

Resources