I'm using a time picker spinner. I would like to implement 30 min intervals.
The code I'm using outputs this effect as shown in the below image.
Here's the code:
picker.setOnTimeChangedListener(new TimePicker.OnTimeChangedListener() {
#Override
public void onTimeChanged(TimePicker view, int hour, int min) {
timeoutput.setText(String.format("%02dh%02d", hour, min));
}
});
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Schedule.this, choosewalk.class);
startActivity(intent);
}
});
#SuppressLint("DefaultLocale")
private void TimeInterval(TimePicker picker) {
try {
int Interval = 30;
NumberPicker minute = (NumberPicker) picker.findViewById(Resources.getSystem().getIdentifier(
"minute", "id", "android"));
minute.setMinValue(0);
minute.setMaxValue((60 / Interval) - 1);
List<String> displayedValue = new ArrayList<String>();
for (int i = 0; i < 60; i += Interval) {
displayedValue.add(String.format("%02d", i));
}
minute.setDisplayedValues(displayedValue.toArray(new String[0]));
} catch (Exception e) {
e.printStackTrace();
}
}
I know that that there are similar questions, but for this specific problem, I'm struggling. I know the method works for intervals of 5, 10, 15, etc. It's altering the code for 30 min intervals that's problematic.
Ok, here's your problem. You want a wheel with 00 and 30 on it, and you want to be able to infinitely scroll it, so it ticks over from 30 to 00 and increments the hour wheel each time, right? Which is basically how the TimePicker works by default.
The issue is this, from NumberPicker:
Note: If the number of items, i.e. the range ( getMaxValue() - getMinValue()) is less than the number of items shown on the selector wheel, the selector wheel will not wrap.
the max - min thing is an extremely awkward way of expressing this (the number of items is actually that + 1) - but basically the spinner shows three items on-screen at a time, and you need to have more than three items (so at least one is off-screen) for wrapping to work. That's why is works for your other intervals (15 mins gives you four items, so that wraps)
Unfortunately I don't think there's a lot you can do about it - the lack of wrapping is hardcoded behaviour in NumberPicker. You could fake it by having four items, 00, 30, 00, 30 but internally that's still values 0 to 3, one rotation of the wheel, not two. And the TimePicker uses those values, comparing to minValue and maxValue to check when the wheel has wrapped and the hour needs to automatically change.
The listener that handles this (in TimePickerSpinnerDelegate) can't be read, so you can't wrap it in a listener that pretends it's going 0 1 0 1 instead. The listener also refers to a bunch of internal private variables and methods, so you can't just copy it into your own code and make the tweaks. You'd have to reimplement the whole widget and its related classes by the looks of things
If it works for you, you could just throw two NumberPickers together and remake it yourself. You'll lose things like the AM/PM functionality, probably accessibility, it depends if you care or not. This basically works:
public class MainActivity extends AppCompatActivity implements NumberPicker.OnValueChangeListener {
private NumberPicker mMinuteSpinner;
private NumberPicker mHourSpinner;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mMinuteSpinner = findViewById(R.id.minPicker);
mHourSpinner = findViewById(R.id.hourPicker);
mMinuteSpinner.setMinValue(0);
mMinuteSpinner.setMaxValue(3);
mMinuteSpinner.setDisplayedValues(new String[]{"00", "30", "00", "30"});
mMinuteSpinner.setOnValueChangedListener(this);
mHourSpinner.setMinValue(0);
mHourSpinner.setMaxValue(23);
String[] hours = new String[24];
for (int i = 0; i < 24; i++) {
hours[i] = Integer.toString(i + 1);
}
mHourSpinner.setDisplayedValues(hours);
}
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
boolean advanced = (newVal == 0 && oldVal == 3) || (newVal == 2 && oldVal == 1);
boolean regressed = (newVal == 3 && oldVal == 0) || (newVal == 1 && oldVal == 2);
if (advanced) {
mHourSpinner.setValue(mHourSpinner.getValue() + 1);
} else if (regressed) {
mHourSpinner.setValue(mHourSpinner.getValue() - 1);
}
}
}
Haven't touched Java in a while! There might be a better way to do that. But yeah, the listener is just checking to see if it's passing between the two rollover points on the four-item list (where it goes from 30 to 00 scrolling one way, or vice versa scrolling the other way). This is basically how the TimePicker works
Related
I have a simple screen with two EditText Boxes and 1 button. I want users to be able to enter various integers into the boxes and the program will perform different operations based on the specific number entered into the box. I'm trying to have them only enter one number at a time but the code wont seem to execute unless both boxes have something in them. And I'm having the if statements check for nulls on the respective boxes before executing to determine which piece of code to execute.
public void button(View view) {
double x, y;
EditText freq1 = findViewById(R.id.freq1);
EditText freq2 = findViewById(R.id.freq2);
TextView str1 = findViewById(R.id.freqanswer);
TextView str2 = findViewById(R.id.injVolt);
TextView error1 = findViewById(R.id.error1);
String strf1, strf2;
strf1 = freq1.getText().toString();
strf2 = freq2.getText().toString();
try {
f1 = Double.parseDouble(strf1);
f2 = Double.parseDouble(strf2);
if ((f1 >= 225) & (f1 <= 312) & (strf1.isEmpty())) {
x = f1 + 20.6;
y = x / 4;
str1.setText(String.format("%.3f", y));
}
}
catch (Exception e){
error1.setText("splat");
}
finally {
InputMethodManager input = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
input.hideSoftInputFromWindow(getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
I included only 1 formula for the sake of brevity, but I'm going to be putting about 6 if statements, checking for number ranges and nulls on this button and I just need it to run with one box being empty. I know the formula works by having play with various outputs, it just won't run with the strf1.isEmpty(). Something has to be in that second box for the formula to execute.
Would appreciate any help
I think you should check before assigning:
if(strf1.isEmpty()){strf1="0";} //if assuming zero does not change the formula's output
if(strf2.isEmpty()){strf2="0";}
f1 = Double.parseDouble(strf1);
f2 = Double.parseDouble(strf2);
this way you are assured of a default value.
I am trying to get the hour component of an object, which is an int, and increment it by 1. So 5 would be 6. I tried to do clocks[i].getHour() = clocks[i].getHour()+1, but this was not allowed and would say I need a variable on the left.
public void daylightSavingsTime(Clock[] clocks) {
for(int i = 0; i <clocks.length; i++) {
int a = clocks[i].getHour()+1;
}
Probably you'd need to write/use a setter function setHour(int newHour) ,
and then you could do something along the lines of:
public void daylightSavingsTime(Clock[] clocks) {
for(int i = 0; i <clocks.length; i++) {
clocks[i].setHour(clocks[i].getHour()+1);
}
Explanation of your statement.
clocks[i].getHour() = clocks[i].getHour()+1;
//To simplify
Clock clock = clocks[i];
clock.getHour() = clock.getHour()+1; //thing you are trying to do.
Suppose clock hours field is 6. What the compiler will do. When it sees clock.getHours() it knows the value is 6. To compiler your statement looks like
6 = 6+1
Obviously no language wants to change the value of 6 to 7
But int a = clocks[i].getHour()+1; is a valid statement as a will be assigned to 7.
To increment the hour in clock just use just do
clock.hours = clocks[i].getHour()+1;
but now hours property is public and can be easily abused like clock.hours = 100; but we may not want it to be 100, but to increase the date as 100 > 24. So use set method like clock.setHour(a+1) this method will internally handle the hour like
Class Clock{
// like that.. it may be different..
void setHour(int hour){
this.day += hour/24;
this.hour += hour%24;
}
}
I'm trying to implement something in my Android application along these lines:
On any certain day if a user opens the app then they click a button, which will increment a number +1. Then can also click that button again which will put the number back to what it was so the number -1.
They can only do this once a day, so at most the number will be +1 from what it was before. But the user can click it and unlick it as many times as they want, it will only still be adding max +1 to the number.
I currently have something implemented: In my database I have a object for updatedTime. I then use a function to check if its on the same day:
private boolean isSameDay(int position){
Date currentDate = new Date();
Date updatedDate = mDataSource.get(position).getUpdated();
// Strip out the time part of each date.
int MILLIS_PER_DAY = 24 * 60 * 60 * 1000;
long julianDayNumber1 = currentDate.getTime() / MILLIS_PER_DAY;
long julianDayNumber2 = updatedDate.getTime() / MILLIS_PER_DAY;
// If they now are equal then it is the same day.
return julianDayNumber1 == julianDayNumber2;
}
Which checks if it's the same day so user can't click on it again. Now I am stumped on figuring out how to make it toggleable so the user can click it again but it will just decrement it, and then user can click it again and it will increment it and so on, until the next day.
This is my OnClickListener for the button, not sure how to implement the toggle function.
habitChecked.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Log.i("In on Click:", ""+position+"");
updateHabit(position);
}
});
And this is my updateHabit method:
private void updateHabit(int position){
Realm.init(mContext);
Realm realm = Realm.getDefaultInstance();
realm.beginTransaction();
if(!isSameDay(position)){ //If the habit hasn't already been updated today
mDataSource.get(position).setTracker(mDataSource.get(position).getTracker()+1);
mDataSource.get(position).setUpdated(new Date()); //update updated date
}
realm.commitTransaction();
}
To summarize: The current functionality is that the user can only click the button once a day which adds the +1, but can't "unclick" it to undo the click and increment, and then reclick it if they want to.
Any help would be appreciated and I can supply any other code that might be relevant.
The code below is supposed to fade two ImageViews, one needs to fade in and the other out depending on the value of counter. For some reason when I run the code I get the following log output:
I/Info: One
I/Info Counter:: 1
I/Info: One
I/Info Counter:: 1
...
It never shows:
I/Info: Two
I/Info Counter:: 0
Can someone explain why this is happening?
Here's the code:
public void fade(View view) {
int counter = 0;
ImageView bale = (ImageView) findViewById(R.id.bale);
ImageView pogba = (ImageView) findViewById(R.id.pogba);
if (counter == 0) {
bale.animate().alpha(0f).setDuration(2000);
pogba.animate().alpha(1f).setDuration(2000);
Log.i("Info", "One");
counter = 1;
} else if (counter == 1){
pogba.animate().alpha(1f).setDuration(2000);
bale.animate().alpha(0f).setDuration(2000);
Log.i("Info", "Two");
counter = 0;
}
Log.i("Info Counter: ", String.valueOf(counter));
}
You're making a logical error, there is nothing syntactically wrong with your code. The scope of counter is where you're having trouble. counter is a local variable, it only exists in the fade(...) method. Every time you call fade() you recreate counter and initialize it to 0. Meaning even though you set it to 1 in the if statement, it will be 0 the next time you call fade(). You either need to make it a class variable or use the alternating approach I describe below.
Non If Statement Alternating Approach:
You don't need an if statement, simply get the alpha of pogba and bale and then when you set their alphas use 1f - pogba.getAlpha() and 1f - bale.getAlpha() (using whichever method returns their alphas). Using this approach will alternate between 1 and 0.
So your fade(View view) method would look similar to the following:
public void fade(View view) {
ImageView bale = (ImageView) findViewById(R.id.bale);
ImageView pogba = (ImageView) findViewById(R.id.pogba);
// I'm not familiar with the method to get the alpha
// so it might not be getAlpha()
bale.animate().alpha(1f - bale.getAlpha()).setDuration(2000);
pogba.animate().alpha(1f - pogba.getAlpha()).setDuration(2000);
}
You would of course need to do the following somewhere else in your code, possibly the constructor.
bale.setAlpha(1f); // I'm not familiar with the method to set the alpha
pogba.setAlpha(0f); // it might be setAlpha(), but I'm not sure
I didn't customize anything on RecyclerView so there's default animation on item added/removed. While I found the animation isn't working as I expected. When I removed item by the following code:
mComments.remove(position);
notifyItemRemoved(position);
I see on UI it always remove the wrong one, and the one should be removed already keeps showing up and overlay the others.
new CountDownTimer(60000, 1000) {
#Override
public void onTick(long l) {
for (int i = 0; i < mComments.size(); i++) {
RoomMessage item = mComments.get(i);
item.timeRemaining -= 1000;
if (item.timeRemaining <= 0) {
Log.v(TAG, "Going to remove no." + i + ". And the content = " + mComments.get(i).text);
removeAt(i);
}
}
}
#Override
public void onFinish() {
start();
}
}.start();
According to log, I did remove the right one. See as below.
02-16 15:26:38.274 21861-21861/com.xxxx.android V/ChatsAdapter: Going to remove no.0. And the content = 1
02-16 15:26:41.284 21861-21861/com.xxxx.android V/ChatsAdapter: Going to remove no.0. And the content = 2
02-16 15:26:42.284 21861-21861/com.xxxx.android V/ChatsAdapter: Going to remove no.0. And the content = 3
What did I do wrong?
btw I've set setisRecyclable(false)
Use only notifyItemRemoved(position);.You are using both. notifyItemRemoved which is for notifying that items previously located at position has been removed from the data set. While notifyItemRangeChanged(int positionStart, int itemCount) is used only when notify any registered observers that the itemCount items starting at position positionStart have changed. If you are adding single item use notifyItemInserted. If you have added more then one new items then use notifyItemRangeInserted(int positionStart, int itemCount). Any method ending with Changed states that the value or values of that particular item or row has changed.