Is there a view for inputing integers in Android? - android

I'm looking for something like the individual parts of the date picker dialog. A view that allows you to input integers (and only integers) that you can limit (between 1 and 10 for example), where you can use the keyboard or the arrows in the view itself. Does it exists?
It is for a dialog. A ready-made dialog to request an integer would also help.

The NumberPicker widget is probably what you want. Unfortunately it's located in com.android.internal.Widget.NumberPicker which we cannot get to through normal means.
There are two ways to use it:
Copy the code from android source
Use reflection to access the widget
Here's the xml for using it in a layout:
<com.android.internal.widget.NumberPicker
android:id="#+id/picker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
Here's the reflection to set the NumberPicker settings (I have not tested this):
Object o = findViewById(R.id.picker);
Class c = o.getClass();
try
{
Method m = c.getMethod("setRange", int.class, int.class);
m.invoke(o, 0, 9);
}
catch (Exception e)
{
Log.e("", e.getMessage());
}
Since it's an internal widget and not in the SDK, future compatibility could be broken if you use reflection. It would be safest to roll your own from the source.
The original source for this information is shared in this Google Group.

The NumberPicker internal widget has been pulled from the Android source code and packaged for your use and you can find it here. Works great!
EDIT: Original link is down, you can find a copy of the widget here

As has been mentioned elsewhere, NumberPicker is now available in the Android SDK as of API 11 (Android 3.0):
http://developer.android.com/reference/android/widget/NumberPicker.html
For Android < 3.0, you can use the code here:
https://github.com/novak/numpicker-demo
https://github.com/mrn/numberpicker

You can with EditText use android:inputType="number"
<EditText android:layout_height="wrap_content" android:id="#+id/editText1" android:inputType="number" android:layout_width="wrap_content"></EditText>

You can simply use an EditText and define inputType as number. E.g:
<EditText
android:id="#+id/etNumberInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:inputType="number" />
To limit the maximum value to, say 10, you can do it programmatically as:
final EditText et = findViewById(R.id.etNumberInput);
et.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {}
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {}
public void onTextChanged(CharSequence s, int start,
int before, int count) {
if (Integer.parseInt(et.getText().toString()) > 10) {
et.setError("***Your error here***");
// your logic here; to limit the user from inputting
// a value greater than specified limit
}
}
});
This should meet your goal.

Related

How to creat a clickable link in a textview?

I am trying to create a clickable link in a textview in a fragment. I think the emulator sees my string as a link but I can't make it clickable. Any suggestions?
In xml
<TextView
android:id="#+id/textViewLink"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:autoLink="all"
android:clickable="true"
android:linksClickable="true"
android:text="#string/link_to_the_website"
android:textColor="#329da8"
android:textSize="17sp" />
In fragment
linkText.setMovementMethod(LinkMovementMethod.getInstance());
linkText.setText(Html.fromHtml(" Read more here"));
linkText.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
linkText = v.findViewById(R.id.textViewLink);
linkText.setMovementMethod(LinkMovementMethod.getInstance());
linkText.setText(Html.fromHtml(" Read more here"));
}
});
In strings.xml
<string name="link_to_the_website">
Read more here
</string>
Simply remove android:autoLink="all" and it should work. When you use setMovementMethod, android:autoLink is not needed as it will override the setMovementMethod.
Also I'm not sure why you are setting the TextViews link in 3 different ways remove the:
Using #string on the XML
Programmatically via code
In the onClick
Firstly I don't think the onClick is needed and secondly pick a choice either set it via
android:text="#string/link_to_the_website"
OR
linkText.setText(Html.fromHtml(" Read more here"));
and not both.
If you use the programmatic method thefromHtml method you are using is deprecated you should instead use fromHtml(String source, int flags) like this:
linkText.setText(Html.fromHtml("<a href=https://google.com> Read more here</a>", Html.FROM_HTML_MODE_LEGACY));
notice the extra parameter Html.FROM_HTML_MODE_LEGACY
or like this if you are targeting devices less than Android Nougat (API Level 24):
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
linkText.setText(Html.fromHtml("<a href=https://google.com> Read more here</a>", Html.FROM_HTML_MODE_LEGACY));
} else {
linkText.setText(Html.fromHtml("<a href=https://google.com> Read more here</a>"));
}
Lastly I'm not sure linking to a hardcoded path on your C dive will work, I tested the above using an actual website i.e.:
linkText.setText(Html.fromHtml("<a href=https://google.com> Read more here</a>", Html.FROM_HTML_MODE_LEGACY));

Create custom preference

I would like to create a SeekBarPreference like preference. I needed range Seekbar. Then I found this library: https://github.com/syedowaisali/crystal-range-seekbar . I would like to create a preference using CrystalRangeSeekbar that will have same look as other preferences.
I use compileSdkVersion = 29, minSdkVersion = 23, targetSdkVersion = 29.
Is that even possible on Android? I spent several hours trying to code something, but I never managed to get same look. I need all padding, margins, caption and summary positions, etc. to be same as in built-in preferences.
Is there any official manual to make custom preferences that will have same look as built-in preferences?
I don't think there is a manual on how to do this, but I had a problem where I needed a ranged seekbar preference for minSdkVersion=22 and what was available at the time did not allow a ranged seek until a later SDK version.
So I just made my own, not sure how exactly it looks compared to the built in preferences
The xml layout snippet is used is
<GridLayout
android:id="#+id/GridLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:orientation="horizontal">
<SeekBar
android:id="#+id/fontSeek"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="0"
android:layout_columnWeight="15"
android:layout_gravity="fill"
android:max="40"
android:padding="6dp"/>
<TextView
android:id="#+id/fontText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_column="1"
android:layout_gravity="center"
android:textStyle="bold"
android:textColor="#color/colorText"
android:typeface="monospace"
android:minEms="2"
android:padding="6dp"/>
</GridLayout>
then in the code I adjusted the textview value to show the adjusted range instead of 0 to 40 by adding 20 to the value.
The extracted Java code associated with xml
int fontSize;
int fontSizeOffset = 20;
fontSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
// Work out the correct values
fontSizeAdjusted = progress;
fontSize = fontSizeAdjusted + fontSizeOffset;
// Update the Textview
fontTextView.setText(String.valueOf(fontSize));
// store pref
SharedPreferences.Editor editor = sharedPref.edit();
editor.putInt("fontSize", fontSize);
editor.apply();
}
public void onStartTrackingTouch(SeekBar seekBar) {
// Do Nothing
}
public void onStopTrackingTouch(SeekBar seekBar) {
// Do Nothing
}
});
You might be able to do better now with Androidx https://developer.android.com/reference/androidx/preference/SeekBarPreference but this was not available when I developed this code.
You should be able to tweak the style to match exactly the standard preference as the docs say it is just a seekbar with optional texview.
You can always look at the source for Androidx to see how they do it e.g. https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/preference/preference/src/main/java/androidx/preference/SeekBarPreference.java
and
https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-master-dev/preference/preference/res/layout/preference_widget_seekbar.xml

Setting a spannable string not working on a simple Textview

I cannot for the life of me understand why this simple code to set a spannable string is not working on this textview. The method below adds a "Today" marker, which should be in green, before the text displaying the date if the date is the current day.
private void setTimeTextView(String timeString) {
Calendar c = Calendar.getInstance();
String todaysDateString = ApiContentFormattingUtil.getFullDateFormat(c.getTime());
if (timeString.equals(todaysDateString)){
String todayText = getResources().getString(R.string.today_marker);
Spannable timeSpannable = new SpannableString(todayText + timeString);
timeSpannable.setSpan(new ForegroundColorSpan(ContextCompat.getColor(getContext(), R.color.greenish_teal)), 0,
todayText.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mDateTime.setText(timeSpannable);
} else {
mDateTime.setText(timeString);
}
}
However, the color won't change.
Here is the XML for this view
<TextView
android:id="#+id/newsfeed_date_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="23dp"
android:textSize="12sp"
android:textColor="#color/white_three"
android:letterSpacing="0.06"
app:fontPath="#string/opensans_bold_path"
tools:text="Monday, January 1st"
android:textAllCaps="true"
tools:ignore="MissingPrefix"
tools:targetApi="lollipop"/>
On versions prior to Oreo, the android:textAllCaps="true" attribute setting will cause the formatting spans to be stripped from your text. You'll need to remove that setting (or set it to false), and handle the conversion to upper case yourself, before creating your SpannableString from it. For example:
String todayText = getResources().getString(R.string.today_marker);
String text = todayText + timeString;
Spannable timeSpannable = new SpannableString(text.toUpperCase());
This is due to a known bug in the platform AllCapsTransformationMethod class, which on versions Nougat 7.1 and below handles the text as a flat String, basically stripping any formatting spans you may have set.
Unfortunately, the support/androidx libraries also use the platform AllCapsTransformationMethod class, so this will happen for their textAllCaps attributes, as well; i.e., app:textAllCaps is broken pre-Oreo, too.
As indicated, this was corrected in Oreo, so this manual fix isn't strictly necessary on those newer versions. However, if you are still supporting pre-Oreo versions, it might be easier to just leave it off and handle the capitalization manually everywhere, rather than having to account for two different setups in your resources and code.

EditText clearComposingText in TextWatcher (Need to remove autocorrect underline in Android OS 4.4)

I'm trying to do something similar to this post (How to remove Android auto-suggest underlining in EditText?) where I want to remove the underline while the user is typing. I am making a rich text editor and do not want the autocomplete underlines to be confused with the underlines that are part of the rich text.
I have a RichTextEditor (which is a rich text editor that extends AppCompatEditText) and with an inner RichTextEditorTextWatcher class. I am doing RichTextEditor.this.clearComposingText() each time the user types, because I do not want to see the underline while the user is typing.
Issue: When I remove the MyEditText.this.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); line, every time the user types, the entire word suggestion is appended as part of any input, which is totally wrong.
e.g. when I type "A", then "d", then "e", I get "AAdAde" in the edit text.
Putting RichTextEditor.this.clearComposingText(); in beforeTextChanged doesn't work either.
What I need is the autocomplete underline removed, with other behavior preserved (i.e. I need textMultiline etc as in my inputType attribute in the XML).
How can I fix this?
NOTE: This problem of the autocomplete underline appearing is only occurring in OS 4.4 (Samsung Galaxy S4). The android:inputType="textNoSuggestions" seems to have no effect on this version of Android, whereas it works on later versions of Android.
public class RichTextEditor extends AppCompatEditText
{
public class RichTextEditorTextWatcher implements TextWatcher
{
#Override
public void afterTextChanged(Editable e)
{
//other implementation not shown here
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count)
{
RichTextEditor.this.clearComposingText();
RichTextEditor.this.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
}
}
}
<com.my.app.RichTextEditor android:id="#+id/rich_text_editor"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:gravity="top"
android:imeOptions="flagNoExtractUi"
android:inputType="textMultiLine|textCapSentences|textLongMessage|textNoSuggestions"
android:isScrollContainer="true"
android:minHeight="100dp"
android:scrollbarAlwaysDrawVerticalTrack="true"
android:scrollbars="vertical" />
I have tried the suggestions here: http://charlesharley.com/2011/programming/disabling-android-textview-suggestions but they don't work on Samsung Galaxy S4. i.e., the following do not work:
<TextView android:inputType="textVisiblePassword" />
<TextView android:inputType="textFilter" />

How can I capture when time changes in a TimePicker if the keyboard is being used?

I have a widget which is a TimePicker that retrieves the time saved in a field in a database.
Thing is that when the user changes the time value in the widget, this is not being saved in the database.
So I came across the setOnTimeChangedListener method that works like a charm, if you are only using the plus and minus signs in the widget. It does not capture the change if you are using the keyword.
Here is my code:
pickedTime.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
public void onTimeChanged(TimePicker arg0, int arg1, int arg2) {
System.out.println("What time is it? "
+ String.valueOf(arg0.getCurrentHour()) + ":"
+ String.valueOf(arg0.getCurrentMinute()));
}
});
I've also tried unsuccessfully:
pickedTime.setOnFocusChangeListener and pickedTime.setOnKeyListener methods.
It didn't work for me when dealing with a dialog and using the TimePicker.
I read somewhere that it's related to the focus, so if u do a clearFocus right before dismissing the dialog it will work.
Something like:
#Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) {
picker.clearFocus();
lastHour=picker.getCurrentHour();
lastMinute=picker.getCurrentMinute();
String time=String.valueOf(lastHour)+":"+String.valueOf(lastMinute);
if (callChangeListener(time)) {
persistString(time);
}
}
}
As mon3t found out, the option is to set android:AddStatesFromChildren="true" in the XML file, as:
<DatePicker
android:id="#+id/datePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:addStatesFromChildren="true" />
<TimePicker
android:id="#+id/timePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:addStatesFromChildren="true" />
Or you can set that by code:
datePicker.setAddStatesFromChildren(true);
timePicker.setAddStatesFromChildren(true);
I really cannot understand what is the point of the default being the way it is.
Sikora's answer is actually adding a lot of value to this common issue.
If you are not managing the change event and look up the value of your time picker from a different piece of code (an onClick handler for a standard button for instance), then the clear focus is needed to get the real value of the time picker when the user manually enters the hours or minutes with the keyboard as opposed to using the up or down arrows or scroller depending on them being on honeycomb or a later version.
Thanks Sikora.

Categories

Resources