Android: animateLayoutChanges(false) programmatically giving NullPointerException - java

This is not duplicate of 'animateLayoutChanges programmatically'.
I want the default animation effects on my view changes except from the fade out effect on removing the objects. I cannot use disableTransitionType() because it was added in API 16. All I could think of was disabling the android:animateLayoutChanges to false, remove the view and setting it again to true. In my recyclerView I thought of removing the animation by holder.rootView.setLayoutTansition(null). But unfortunately it is giving me NullPointerException.
A part of my code is something like this:
#Override
public void onBindViewHolder(final MyViewHolder holder, int position) {
SavedMessagePackage current = data.get(position);
final String message = current.message;
holder.message.setText(message);
holder.message.setMaxLines(2);
holder.message.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (holder.button.getVisibility() == View.GONE) {
holder.button.setVisibility(View.VISIBLE);
holder.message.setMaxLines(Integer.MAX_VALUE);
holder.message.setText(message);
}
else if (holder.button.getVisibility() == View.VISIBLE) {
holder.root_view.setLayoutTransition(null); // NullPointerException
holder.button.setVisibility(View.GONE);
holder.message.setMaxLines(2);
holder.root_view.setLayoutTransition(new LayoutTransition());
}
}
});
holder.button.setVisibility(View.GONE);
}
How can I achieve this?

In your case you could have holder or root_view being null, but since holder was accessed successfully before, so root_view is null.
Therefore it's most likely you didn't assign holder.root_view before.

Related

Checks wrong checkbox on recyclerview

i have the following code. If the name of the checkbox is in the 'deneme' array that the function takes, I want the checkbox to be checked. but those that don't enter the 'if' are marked strangely. and there are random checked when scrolling up and down
public SubjectRecyclerViewAdapter(ArrayList<Subject> subjects, ArrayList<String> deneme) {
this.subjects = subjects;
this.deneme = deneme;
}
#Override
public void onBindViewHolder(#NonNull SubjectRecyclerViewAdapter.MyViewHolder holder, int position) {
holder.checkBox.setText(subjects.get(position).getCheckBoxSubject());
if (deneme.contains(subjects.get(position).getCheckBoxSubject())) {
holder.checkBox.setChecked(true);
}}
Because the ViewHolders are recycled (meaning they are reused as you scroll) you need to explicitly set the checkbox's state either way (so that it changes whatever previous state the ViewHolder had):
if (deneme.contains(subjects.get(position).getCheckBoxSubject())) {
holder.checkBox.setChecked(true);
} else {
holder.checkBox.setChecked(false);
}

Recyclerview Layout Manager Get View in Position After Scrolling in Android

Recyclerview is scrolling with it's LinearLayoutManager like that lm.scrollToPositionWithOffset(position, offset). How to get the view where in scrolled position before scrolling? The view that will scrolled returning null after scrolling because still not created. I've try Runnable, Observer and onLayoutCompleted but still null. How to get the view?
lm.scrollToPositionWithOffset(position, offset);
recyclerView.post(new Runnable(){
#Override
public void run(){
View v1 = recyclerView.getChildAt(position); // returning null.
View v2 = recyclerView.getLayoutManager().getChildAt(position); // returning null.
}
});
recyclerView.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
View v1 = recyclerView.getChildAt(position); // returning null.
View v2 = recyclerView.getLayoutManager().getChildAt(position); // returning null.
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}});
#Override // in LinearLayoutManager
public void onLayoutCompleted(RecyclerView.State state) {
super.onLayoutCompleted(state);
View v1 = recyclerView.getChildAt(position); // returning null.
View v2 = this.getChildAt(position); // returning null.
}
View v = lm.getChildAt(position);
lm.scrollToPositionWithOffset(position, offset);
v.post(new Runnable() {
#Override
public void run() {
// View is ready here.
});
If you're trying to modify the view content, you should do this:
Modify your current model: itemList.get(position) // and change
any property here to handle that state
Call adapter.notifyItemChanged(position)
Make sure you have the right logic on your ViewHolder to handle
this changes and that should modify your View
But if you really wanna change things through the ViewHolder you can also do this: recyclerView.findViewHolderForAdapterPosition(position) and then:
if (null != holder) {
holder.itemView.findViewById(R.id.YOUR_ID) // call any method do you want to
}
I really recommend the first option, but that's up to you. Hope this helps you!

Android Firebase RecyclerView Adapter Remove Views

I am facing a Firebase RecyclerView problem where I cannot remove unwanted CardViews from my RecyclerViews. In my code I check the city's name and the guide's chosen city to match them. It populates guide's details only if the guide's city matches the picked city, but it also shows empty cardview with default layout.
guideDataRef = FirebaseDatabase.getInstance().getReference().child("Guides");
public void recycler() {
super.onStart();
try {
//Guide RecyclerView
Query guideQuery = guideDataRef.orderByKey();
guideQuery.keepSynced(true);
FirebaseRecyclerOptions guideOptions =
new FirebaseRecyclerOptions.Builder<UserModelClass>().setQuery(guideQuery, UserModelClass.class).build();
guideAdapter = new FirebaseRecyclerAdapter<UserModelClass, guideViewHolder>(guideOptions) {
#Override
protected void onBindViewHolder(#NonNull guideViewHolder holder, final int position, #NonNull final UserModelClass model) {
String pickedcity = model.getPickedCity();
String postname = (String) cityName.getText();
if(pickedcity.equals(postname)) {
final String guide_key= getRef(position).getKey();
holder.setGuideName(model.getName());
holder.setGuideSurname(model.getSurName());
holder.setGuideImage(getApplicationContext(), model.getPhotoURL());
// holder.mView.setVisibility(View.VISIBLE);
//Guide Click listener
holder.mView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent guideHireIntent = new Intent(getApplication(), GuideHireActivity.class);
guideHireIntent.putExtra("guide_id", guide_key);
finish();
startActivity(guideHireIntent);
}
});
}
}
#NonNull
#Override
public guideViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout_guides, parent, false);
return new guideViewHolder(view);
}
#Override
public void onError(DatabaseError e){
Toast.makeText(getApplicationContext(), "Error by stopping ", Toast.LENGTH_SHORT).show();
}
#Override
public int getItemCount() {
return super.getItemCount();
}
#Override
public void onDataChanged() {
super.onDataChanged();
notifyDataSetChanged();
}
};
guideAdapter.notifyDataSetChanged();
guideRecyclerView.setAdapter(guideAdapter);
guideAdapter.startListening();
} catch (DatabaseException e) {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
}
}
enter image description here
enter image description here
I can change the adapter visibility to gone if it does not match with the requirements but the problem is that after making it's visibility gone it is still there holding the place (but invisible - there's still an empty space). How can I avoid populating an item from the recycler view completely, instead of making it invisible if the requirements do not match?
You're not showing what guideDataRef is in your code, so I'm assuming that it's just aDatabaseReference object for everything beneath a \Guides node.
If you're doing that, you're going to get a call for onBindViewHolder for every child at that particular location. This means that you're going to be asked to make a view for every child. You cannot choose whether or not a view will appear for that item.
It looks like you're assuming that your if statement in onBindViewHolder method will skip over those items. But what's actually happening is that you're simply allowing an empty view to occupy that spot in the list.
Instead, you should come up with a query that generates only the items of interest to your list. This means you'll have to tell Firebase to filter for children that meet your criteria.
You can also read the entire contents of the location, manually filter out the items you don't want, and build a list of items you do want. You can then build an custom adapter with that list, and it can then become the input to a ListView or even better to a RecyclerView.

Setting OnClickListeners for Dynamically added views

I am adding a small view to a linearlayout. I have to apply a View.OnClickListener to it, but even though the view has been added, the onClick still does not fire. Here's my method
for (Streams stream : streamArray) {
streamCount++;
if (!(streamCount > 3)) {
// ADD AN ITEM
View v = li.inflate(R.layout.stream_item, theLinearLayoutforStreamItems, false);
//SET ONCLICK
v.setOnClickListener(new android.view.View.OnClickListener() {
public void onClick(View v) {
Log.i("onclick", ""+position );
}
});
txtStreamItem = (TextView) v.findViewById(R.id.txtViewStream_item);
txtStreamItem.setText(stream.name);
theLinearLayoutforStreamItems.addView(v);
}
The onClick()does not fire. I do not know why, and I cannot find any thing on the internet on it.
I think what you really want to achieve is:
txtStreamItem.setOnClickListener(new android.view.View.OnClickListener() {
public void onClick(View v) {
Log.i("onclick", ""+position );
}
});
Put it just below this line:
txtStreamItem = (TextView) v.findViewById(R.id.txtViewStream_item);
Set View.setClickable & focus-able true.

Set EditText visibility based on Spinner value

I'm trying to create this dialog:
.
When Spinner is set to custom value, TextEdit should automatically appear. I'm calling View.setVisible() on the TextView but the visibility is not evaluated immediately but waits to another change - e.g. adding another row or setting a date.
The code:
...
customText = (EditText) v.findViewById(R.id.edit_custom_text);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
s.setAdapter(adapter);
s.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
SpinnerItem si = (SpinnerItem) adapterView.getItemAtPosition(i);
evt.type = si.eventType;
if (evt.type == EventType.CUSTOM) {
customText.setVisibility(View.VISIBLE);
} else {
customText.setVisibility(View.GONE);
}
}
#Override
public void onNothingSelected(AdapterView<?> adapterView) {
//do nothing
}
});
I tried View.invalidate() (on parent view) and View.refreshDrawableState() with no luck :/
Edit: The code above is reached (verified by debugger) and I also tried View.INVISIBLE. The view is just not refreshed immediately but only after another change in view.
For Example see this
s.setOnItemSelectedListener(new OnItemSelectedListener() {
#Override
public void onItemSelected(AdapterView<?> parentView,View selectedItemView, int position, long id) {
if ("YES".equals(s.getSelectedItem().toString().toUpperCase())) {
youredittxt.setVisibility(View.VISIBLE);
} else if ("NO".equals(s.getSelectedItem().toString().toUpperCase())) {
youredittxt.setVisibility(View.INVISIBLE);
}}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
});
That should work, could it be that your layout somehow doesn't allow/recognises this change perhaps?
Try changing it to INVISIBLE instead of GONE, including (important!) in your layout xml file.
If that works for some reason, try something like this:
customText.getParent().requestLayout(); //possibly the parent of that etc
As a follow up question, are you in the main UI thread? Because Android have some built in features and policies, so only the owning thread will be able to change the UI.
If you are outside the same thread, try:
customText.getHandler().post(new Runnable() {
public void run() {
customText.setVisibility(View.VISIBLE);
}
});
Hope this helps! :)
Verify that you are actually reaching your code block.
customText.setVisibility(View.GONE);

Categories