I implemented ItemDecoration into my RecyclerView along with an Animation that plays whenever the RV is loaded. However, I noticed that the decoration appears already at the bounds before the animation completes, and I want to have the decoration move in with the animation at the same time. How would I do this?
So far, I have been entering the animation like so:
#Override
public void onBindViewHolder(final RecyclerVH recyclerVH, final int position) {
currentNote = data.get(position);
final String currentTitle = currentNote.getTitle();
final String currentContent = currentNote.getContent();
final int currentPosition = currentNote.getPosition();
String currentAlarmDate = currentNote.getAlarm();
Log.d("RecyclerView", "onBindVH called: " + currentTitle);
Log.d("RecyclerView", "Position at: " + currentPosition + " and Adapter Position at: " + recyclerVH.getAdapterPosition());
// final Info currentObject = data.get(position);
// Current Info object retrieved for current RecyclerView item - USED FOR DELETE
recyclerVH.listTitle.setText(currentTitle);
recyclerVH.listContent.setText(currentContent);
Log.d("RecyclerAdapter", "currentAlarmDate is: '" + currentAlarmDate + "'");
if (currentAlarmDate != null && !currentAlarmDate.equals(" ")) {
Log.d("RecyclerAdapter", "Current Alarm set for: " + currentAlarmDate);
recyclerVH.alarm.setText(currentAlarmDate);
} else
recyclerVH.alarm.setText(R.string.no_alarm);
/*recyclerVH.listTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Open new Activity containing note content
Toast.makeText(this, "Opening: " + currentObject.title, Toast.LENGTH_LONG).show();
}
});*/
runEnterAnimation(recyclerVH.itemView, position);
}
private void runEnterAnimation(View itemView, int position) {
// Starts Animation
Animation animation = AnimationUtils.loadAnimation(context,
position >= lastAnimatedPosition ? R.anim.up_from_bottom : R.anim.down_from_top);
// If true, up_from_button is loaded
itemView.startAnimation(animation);
lastAnimatedPosition = position;
Log.d("RecyclerAdapter", "lastAnimatedPosition is now: " + lastAnimatedPosition);
}
Seems like #Mimmo Grottoli's answer is the closest thing to a solution. Check out this post: How to disable RecyclerView item decoration drawing for the duration of item animations
You can read the documentation
Or if need to animated decoration you can try this:
https://github.com/slidenerd/materialtest
Thanks, if you not get your solution from it than please ask me i will try my best to give you a better solution. :)
Related
how can I limit the number of checked checkboxes in android? I have multiple checkboxes being added programatically and it's difficult to keep track of them.
here's the code used to add them:
final CheckBox currentVariantCheckbox = new CheckBox(getApplicationContext());
checkBoxGroupList.add(currentVariantCheckbox);
Log.d(TAG, "onDataChange: added " + currentVariantCheckbox + " to the checkboxgrouplist; size = " + checkBoxGroupList.size());
currentVariantCheckbox.setChecked((Boolean) currentVariant.child("checked").getValue());
LinearLayout checkboxGroupLayout = new LinearLayout(getApplicationContext());
checkboxGroupLayout.setOrientation(LinearLayout.HORIZONTAL);
currentVariantCheckbox.setText(currentVariant.child("name").getValue(String.class));
TextView currentVariantPriceTag = new TextView(getApplicationContext());
checkboxGroupLayout.addView(currentVariantCheckbox);
if (currentVariant.child("price").exists()) {
currentVariantPriceTag.setText("+" + currentVariant.child("price").getValue(float.class).toString() + " €");
checkboxGroupLayout.addView(currentVariantPriceTag);
ok so instead of using a onCheckedStateChangedLister I used OnClickListener. And I created an ArrayList to keep track of all the checked checkboxes:
final ArrayList<CheckBox> checkedList = new ArrayList<>();//this is the list to keep track of checked checkboxes
int maxOptions = 3
int minOptions = 1
currentVariantCheckbox.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Boolean currentCheckState = currentVariantCheckbox.isChecked();
if (currentCheckState) {//if the clicked checkboxes was unchecked and is now checked
checkedList.add(currentVariantCheckbox);
Log.d(TAG, "onClick: added " + currentVariantCheckbox + " ;checkedList.size is now: " + checkedList.size());
if (checkedList.size() >= maxOptions) {
checkedList.get(0).setChecked(false);
checkedList.remove(0);// if limit exceeded remove the first element from the checked list
Log.d(TAG, "onCheckedChanged: checkedList's size is now: " + checkedList.size());
}
} else if (checkedList.size() <= minOptions) {
currentVariantCheckbox.setChecked(true);
// if the list is empty just add the clicked checkbox to the list for example here 0
// and it will be checked automatically
} else {
checkedList.remove(currentVariantCheckbox);
// if the checkbox was already checked and no limit is exceeded
// then it will be unchecked therfore it should be removed from checkedList
}
}
});
I have a custom view called TinderStackLayout.
At a certain part of the code I am deleting a child view of it and re-adding it back at the last position possible -
private void handleViewAfterAnimation(View view, boolean shouldSkipView) {
Log.d("card view - ", "inside handleViewAfterAnimation");
isCardAnimating = false;
TinderStackLayout tinderStackLayout = (TinderStackLayout) view.getParent();
if (tinderStackLayout == null)
return;
tinderStackLayout.removeView(view);
if (shouldSkipView)
tinderStackLayout.addCard((TinderCardView) view, tinderStackLayout.getChildCount() - 1);
//this part is for debugging purpose
for (int i = 0; i < tinderStackLayout.getChildCount(); i++) {
View childAt = tinderStackLayout.getChildAt(i);
if (childAt instanceof TinderCardView)
Log.d("card view - ", "child cards after deletion - " + (((TinderCardView) childAt).usernameTextView.getText()));
}
}
here is my addCard() method -
public void addCard(TinderCardView tinderCardView, int addToPosition) {
View topCard = getChildAt(0);
if (topCard != null && topCard.equals(tinderCardView)) {
return;
}
topCardOnStack = tinderCardView;
ViewGroup.LayoutParams layoutParams;
layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
addView(tinderCardView, addToPosition, layoutParams);
// tinderCardView.animate()
// .x(0)
// .setInterpolator(new AnticipateOvershootInterpolator());
}
What I don't understand is what I get in the UI -
I have 3 cards.
I press the button, one card is being animated away, the second one is being shown. I press the button again, the second one animates away. I press the last one and the button does not work anymore. What I want to achieve is the first card appearing now behind the last one.
Here is what I get when logging the values out -
seems correct, it was before clicking 3 2 1 and now 2 3 1. The next one should be 1 2 3, but this is what I get for the next one -
goes back to 3 2 1 instead of 1 2 3. I can't figure out why. ?
Edit:
found the reason why this is happening, I am giving a view which should always be the top card on the stack but I am actually not giving the top card because I am always adding a new card. Here is the method -
public void handleButtonPressed(int buttonTag) {
Log.d("card view - ", "inside handleButtonPressed");
TinderStackLayout tinderStackLayout = ((TinderStackLayout) this.getParent());
TinderCardView topCard = (TinderCardView) tinderStackLayout.getChildAt(tinderStackLayout.getChildCount() - 1);
if (isCardAnimating) {
return;
}
switch (buttonTag) {
case DELETE_BUTTON_PRESSED:
isCardAnimating = true;
deleteCard(topCard);
break;
case PASS_BUTTON_PRESSED:
Log.d("card view - ", "inside pass button pressed");
isCardAnimating = true;
passCard(topCard);
Log.d("card view - ", "top card Value before pass - " + topCard.displayNameTextView.getText());
Log.d("card view - ", "child count - " + tinderStackLayout.getChildCount());
for (int i = 0; i < tinderStackLayout.getChildCount(); i++) {
View childAt = tinderStackLayout.getChildAt(i);
if (childAt instanceof TinderCardView)
Log.d("card view - ", "child cards before deletion - " + (((TinderCardView) childAt).usernameTextView.getText()));
}
break;
case APPROVE_BUTTON_PRESSED:
showLawyerContactDetailsFragment(topCard);
break;
}
}
I am trying to do TinderCardView topCard = (TinderCardView) tinderStackLayout.getChildAt(tinderStackLayout.getChildCount() - 1) in order to get the top card in my stack, which would be correct if I delete the cards and not re-add them to my stack but that is not the case when re-adding them. What should be the solution for always getting the top card when I am adding new views all the time?
If you want to shuffle cards, then you don't need to delete and re-add them. You simply need a data structure, which will do it for you. For your use case you can use Circular Array.
private CircularArray cardArray; //declaration
Now when you are adding your views, add it to your card array also.
cardArray.addLast(tinderCardView);
addView(tinderCardView); // add to your layout.
Then use this code to check.
int shuffleCount = 3;
for (int i = 1; i <= shuffleCount; i++)
shuffleTopCard(i);
Finally shuffleTopCard() method.
private void shuffleTopCard(int shuffleID) {
Log.d(TAG, "shuffleTopCard: cards before shuffle");
for (int i = 0; i < cardCount; i++)
Log.d(TAG, "shuffleTopCard: " + ((TinderCardView) cardArray.get(i)).getTag());
TinderCardView cardView = (TinderCardView) cardArray.popLast();
Log.e(TAG, "shuffleTopCard: top cardID = " + cardView.getTag());
cardArray.addFirst(cardView);
Log.d(TAG, "shuffleTopCard: cards after shuffling " + shuffleID + " time");
for (int i = 0; i < cardArray.size(); i++)
Log.d(TAG, "shuffleTopCard: " + ((TinderCardView) cardArray.get(i)).getTag());
Log.e(TAG, "shuffleTopCard: after shuffle top card = " + ((TinderCardView) cardArray.getLast()).getTag());
}
Use of CircularArray will free you from head-ache of maintaining card position manually and also separates your CustomViewGroup and card shuffling logic thereby resulting in loosely-coupled code.
In Realm addchangelistener can we know at which position list got changed, and does the element got inserted/updated/removed from the list ??
can we know at which position list got changed
Yes
private RealmResults<Obj> results;
private OrderedRealmCollectionChangeListener<RealmResults<Obj>> changeListener = new OrderedRealmCollectionChangeListener<RealmResults<Obj>>() {
#Override
public void onChange(RealmResults<Obj> results, OrderedCollectionChangeSet changeSet) {
String insertions = changeSet.getInsertions().length == 0 ? "" : "\n - Insertions: " + Arrays.toString(changeSet.getInsertions());
String deletions = changeSet.getDeletions().length == 0 ? "" : "\n - Deletions: " + Arrays.toString(changeSet.getDeletions());
String changes = changeSet.getChanges().length == 0 ? "" : "\n - Changes: " + Arrays.toString(changeSet.getChanges());
showStatus("Obj was loaded, or written to. " + insertions + deletions + changes);
}
};
public void ...() {
results = realm.where(Obj.class)...findAllAsync();
results.addChangeListener(changeListener);
I had been debugged the following code for whole day, and have no idea why it doesn't work as expected.
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.animation.PropertyValuesHolder;
import com.nineoldandroids.animation.ValueAnimator;
private void animateThumbCoorToMatchCurrentIndixes() {
float newThumbLeftCoor = this.indexToCoor(this.thumbLeftIndex);
float newThumbRightCoor = this.indexToCoor(this.thumbRightIndex);
PropertyValuesHolder thumbLeftPropertyValuesHolder = PropertyValuesHolder.ofFloat("thumbLeftCoor", this.thumbLeftCoor, newThumbLeftCoor);
PropertyValuesHolder thumbRightPropertyValuesHolder = PropertyValuesHolder.ofFloat("thumbRightCoor", this.thumbRightCoor, newThumbRightCoor);
Log.i("CHEOK", "Animate " + this.thumbLeftCoor + " -> " + newThumbLeftCoor);
Log.i("CHEOK", "Animate " + this.thumbRightCoor + " -> " + newThumbRightCoor);
ValueAnimator valueAnimator = ObjectAnimator.ofPropertyValuesHolder(this, thumbLeftPropertyValuesHolder, thumbRightPropertyValuesHolder);
valueAnimator.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
valueAnimator.setRepeatCount(0);
valueAnimator.setInterpolator(new DecelerateInterpolator());
Log.i("CHEOK", "Animation duration = " + valueAnimator.getDuration());
valueAnimator.start();
}
// Do not remove this code. It is used for reflection call for animation.
#SuppressWarnings("unused")
private void setThumbLeftCoor(float thumbLeftCoor) {
this.thumbLeftCoor = thumbLeftCoor;
Log.i("CHEOK", "SET thumbLeftCoor " + thumbLeftCoor);
this.postInvalidate();
}
// Do not remove this code. It is used for reflection call for animation.
#SuppressWarnings("unused")
private void setThumbRightCoor(float thumbRightCoor) {
this.thumbRightCoor = thumbRightCoor;
Log.i("CHEOK", "SET thumbRightCoor " + thumbRightCoor);
this.postInvalidate();
}
My console log is as follow :
Animate 636.0985 -> 0.0
Animate 679.27057 -> 578.0
Animation duration = 200
However, methods setThumbLeftCoor and setThumbRightCoor never get triggered.
Anyone have idea why it happens so?
All the while, by having setThumbLeftCoor and setThumbRightCoor as private method work for my case.
Just that recently, a child class is being derived from the above class.
To make the above code work as it is, changing setThumbLeftCoor and setThumbRightCoor to public method is required. (Even protected won't work)
My guess is, this is due to limitation of "reflection"
I'm looking for instantiate dynamically a numberpicker. I want to place a value (kitQty - YourQty) in numberpicker order.
The next code is now working but only for the last one Id=9.
Because this only working with the last record?
Try setTag and setId and I can not change the numberpicker that desire. Anyone know what may be wrong in my code?
Thank you very much!
public class MyKits extends Fragment {
private Button performAudit;
private Button submitOrder;
NumberPicker yourQty;
NumberPicker kitQty;
NumberPicker order;
Conexion basedatos;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_mykits, container, false);
Context context=v.getContext();
basedatos=new Conexion(v.getContext());
TextView tvModel = (TextView) v.findViewById(R.id.tvModel);
TableLayout table= (TableLayout) v.findViewById(R.id.Tabla);
tvModel.setText(getArguments().getString("model"));
for(int i=0;i<10;i++)
{
TableRow tR = new TableRow(v.getContext());
LinearLayout l1= new LinearLayout(v.getContext());
LinearLayout l2= new LinearLayout(v.getContext());
LinearLayout l3= new LinearLayout(v.getContext());
LinearLayout l4= new LinearLayout(v.getContext());
Button item = new Button(v.getContext());
kitQty = new NumberPicker(getActivity().getApplicationContext());
yourQty= new NumberPicker(getActivity().getApplicationContext());
order= new NumberPicker(getActivity().getApplicationContext());
item.setText("Prueba Imparjdsbfjbdsjfgbijsdfgijnsfdignsidfgh");
l1.addView(kitQty);
l2.addView(item);
l3.addView(yourQty);
l4.addView(order);
///Tamaño Texto
item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
kitQty.setMaxValue(100);
kitQty.setValue(50);
kitQty.setMinValue(0);
kitQty.setEnabled(false);
order.setMinValue(0);
order.setMaxValue(kitQty.getMaxValue());
yourQty.setMaxValue(kitQty.getMaxValue());
yourQty.setMinValue(0);
yourQty.setTag(i);
yourQty.setId(i);
order.setTag(i);
order.setId(i);
kitQty.setTag(i);
kitQty.setId(i);
yourQty.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Log.e("oldValue: " + oldVal + " ID: " + picker.getId(), " newVal: " + newVal + " ID: " + picker.getTag());
kitQty.setId(picker.getId());
yourQty.setId(picker.getId());
order.setId(picker.getId());
order.setValue(kitQty.getValue() - yourQty.getValue());
}
});
order.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
#Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
Log.e("oldValue: " + oldVal + " ID: " + picker.getId(), " newVal: " + newVal + " ID: " + picker.getTag());
kitQty.setTag(picker.getTag());
yourQty.setTag(picker.getTag());
order.setTag(picker.getTag());
order.setValue(kitQty.getValue() - yourQty.getValue());
// calcularQty(picker);
}
});
tR.addView(l1);
tR.addView(l2);
tR.addView(l3);
tR.addView(l4);
table.addView(tR);
}
return v;}
public static MyKits newInstance(String model) {
MyKits f = new MyKits();
Bundle b = new Bundle();
b.putString("model", model);
f.setArguments(b);
return f;} }
Well, there are a few things wrong in your code...
But let's just focus on the main question in saying first that you should not assign id by yourself. I'd rather either inflate each of them with a granular xml layout file, or if you insist on creating your widgets using "new", then leave the id alone and Android should assign them properly.
But really the main reason why your code don't work is that you assign widget ids in a "for" loop with your counter variable (i) and you are using the same value as an id for order widget, yourQty widget and kitQty widget. You need to understand that each widget id must be unique in the same view hierarchy. First start by fixing this issue. But I won't tell you how: you should be able to fix this by yourself.