I am using this class to draw TriangleShapeView over ImageView that changes its color and drawable image upon user click event.
in RecyclerView onBindViewHolder method, i check against
feedModel.isSubscribed() then set TriangleShapeView color and drawable image accordingly:
public void onBindViewHolder(FeedViewHolder holder, final int position) {
final FeedModel feedModel =this.feedCollection.get(position);
if (feedModel.isSubscribed()) {
holder.mTrView.setBackgroundColor(Color.RED);
holder.mTrView.setDrawable(holder.mTrView.getContext().getResources().getDrawable(R.drawable.ic_check));
} else {
holder.mTrView.setBackgroundColor(Color.BLACK);
holder.mTrView.setDrawable(holder.mTrView.getContext().getResources().getDrawable(R.drawable.ic_plus));
}
in setOnClickListener:
holder.itemView.setOnClickListener(v -> {
if (FeedAdapter.this.onItemClieckListener != null){
FeedAdapter.this.onItemClieckListener.onFeedItemClicked(feedModel);
if (feedModel.isSubscribed()) {
feedModel.setIsSubscribed(false);
notifyItemChanged(position);
} else {
feedModel.setIsSubscribed(true);
notifyItemChanged(position);
}
}
});
this works fine when items get loaded for first time but when user clickes:
- 1st & 2nd time: drawable image got changes as desired but the color
remains same.
- 3rd time both drawable image and color gets changes
i am using the following xml layout to inflate this custom view:
<cardView
<RelativeLayout
....
<com.xxx.TriangleShapeView
android:id="#+id/trView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:elevation="15dp"
TriangleShapeView:imgPadding="5dp"
TriangleShapeView:triangleBackground="#color/cardview_dark_background"
TriangleShapeView:img="#drawable/ic_plus"/>
i believe, the FeedModel gets updated once OnClick is called and checks are fine in onBindViewHoldr method. so i think the problem is in the class mentioned in the above link
What i am looking to achieve is:
if feedModel.isSubscribed then change the color to red and drawable to check-sign icon. else, keep the initial values as in the layout xml.
also react upon onClick and change the color and image
I think you're right and the error in this method.
public void setBackgroundColor(int backgroundColor) {
this.backgroundColor = backgroundColor;
invalidate();
}
the paint color get assigned in the constructor and onDraw method.
try to add to this method before invalidate() the line with paint.setColor(backgroundColor);
Related
So essentially, I have a recyclerview that has a list of levels. But essentially, I want certain items to have a black colored background to suggest that they are not locked yet.(kind of like in video games)
my current method:
#Override
public void onBindViewHolder(BracketsAdapter.ViewHolder viewHolder, int position) {
// Get the data model based on position
Bracket bracket = bracketsList.get(position);
int color = UserPreferences.getInstance().getBracket();
// Set item views based on your views and data model
TextView textView = viewHolder.nameTextView;
textView.setText(bracket.toString());
Log.d("Bracket level", ""+bracket.getId());
if(color < bracket.getId()) {
textView.setBackgroundResource(R.color.black); // suggests level is locked
}
}
The issue with this method, is that it works initially but the moment I scroll down and back up, items that should not be colored end up being colored. Why is this? Is there a better way of implementing this?
Recycle view always reuses the old view so you are getting that problem, To solve the problem, you should set color every time calling bindViewHolder, So try to do like this,
if(color < bracket.getId()) {
textView.setBackgroundResource(R.color.black); // suggests level is locked
} else {
textView.setBackgroundResource(R.color.defaultcolor); // default color
}
this will work fine.
I have a logo view, which is a full screen fragment containing single ImageView.
I have to perform some operations after the logo image is completely visible.
Following code is used to invoke the special task
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ImageView logoImageMaster = new ImageView(getContext());
//logoImageMaster.setImageResource(resID); //even after removing this, i am getting the callback twice
try {
// get input stream
InputStream ims = getActivity().getAssets().open("product_logo.png");
// load image as Drawable
Drawable d = Drawable.createFromStream(ims, null);
// set image to ImageView
logoImageMaster.setImageDrawable(d);
}
catch(IOException ex) {
}
logoImageMaster.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() { //FIXME get called twice. Check this out, no info to distinguish first from second
// Log.e("PANEL", "onGlobalLayout of Logo IV ---------------------------------");
activityInterface.doSpecialLogic();
}
});
return logoImageMaster;
}
My exact problem is, onGlobalLayout is called twice for this view hierarchy.
I know that onGlobalLayout is invoked in performTraversal of View.java hence this is expected.
For my use case of Single parent with Single child view, I want to distinguish the view attributes such that doSpecialLogic is called once[onGlobalLayout is called twice] , after the logo image is completely made visible.
Please suggest some ideas.
OnGlobalLayoutListener gets called every time the view layout or visibility changes. Maybe you reset the views in your doSpecialLogic call??
edit
as #Guille89 pointed out, the two set calls cause onGlobalLayout to be called two times
Anyhow, if you want to call OnGlobalLayoutListener just once and don't need it for anything else, how about removing it after doSpecialLogic() call??
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
//noinspection deprecation
logoImageMaster.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
logoImageMaster.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
activityInterface.doSpecialLogic();
It seems to be called one time for each set done over the imageView
logoImageMaster.setImageResource(resID);
logoImageMaster.setImageDrawable(d);
You should Try using kotlin plugin in android
This layout listener is usually used to do something after a view is measured, so you typically would need to wait until width and height are greater than 0. And we probably want to do something with the view that called it,in your case
Imageview
So generified the function so that it can be used by any object that extends View and also be able to access to all its specific functions and properties from the function
[kotlin]
inline fun <T: View> T.afterMeasured(crossinline f: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (measuredWidth > 0 && measuredHeight > 0) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
f()
}
}
})
}
[/kotlin]
Note:
make sure that ImageView is described properly in the layout. That is its layout_width and layout_height must not be wrap_content. Moreover, other views must not result in this ImageView has 0 size.
I've a requirement in which an ImageView's enabled state is changed.
I have 2 images: one for the enabled state & another for the disabled state.
Without using a selector, how can I change the Image src when the setEnabled(true/false) is changed?
That is:
imageView.setEnabled(true);
imageView - use image imgEnabled.png
imageView.setEnabled(false);
imageView - use image imgDisabled.png
Thank You
Try this
if(imageView.isEnabled())
{
imageView.setBackgroundResource(R.drawable.imgEnabled);
}
else
{
imageView.setBackgroundResource(R.drawable.imgDisabled);
}
You can do it by setting the image yourself using setImageResource.
But this may not be appropriate, since your view's state may be changed from your code anywhere.
imageView.setEnabled(true);
imageView.setImageResource(R.drawable.imgEnabled);
imageView.setEnabled(false);
imageView.setImageResource(R.drawable.imgDisabled);
You can also write your own class that extends ImageView
and override the following method
#Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if(isEnabled())
{
//set drawable for enabled state here
}
else
{
//set drawable for disabled state here
}
}
you can use this to change image resource-
imageView.setBackgroundResource(R.drawable.image);
I have a LinearLayout containing both a ListView and an EditText. When the On-Screen keyboard is launched by touching the EditText, the ListView resizes so that only the top few elements remain visible.
The context that the ListView is being used in has the bottom few elements being more visually relevant than the top, and so I'd like for it to resize so that the bottom remains visible, rather than the top. Any pointers?
(Incidentally, the current fix I'm using involves using smoothScrollToPosition, but the laggy scroll behaviour makes this undesirable)
I just solved a similar issue this morning, and thought I'd post my result here for the benefit of future searchers. My issue was that scrolling to the bottom wasn't helping since I was calling it before the view actually changed size. The solution? Wait until it does change size by using a GlobalLayoutListener
Steps:
1) implement the following method in the activity holding the listview
public void scrollToBottom(){
//I think this is supposed to run on the UI thread
listView.setSelection(mAdapter.getCount() - 1);
}
2) create the following class
public class OnGlobalLayoutListenerWithScrollToBottom implements OnGlobalLayoutListener{
private boolean scroll;
private OnScrollToBottomListener listener;
public interface OnScrollToBottomListener{
public void scrollToBottom();
}
public OnGlobalLayoutListenerWithScrollToBottom(OnScrollToBottomListener listener){
this.listener = listener;
}
#Override
public void onGlobalLayout() {
if(scroll){
listener.scrollToBottom();
scroll = false;
}
}
/**
* Lets the listener know to request a scroll to bottom the next time it is layed out
*/
public void scrollToBottomAtNextOpportunity(){
scroll = true;
}
};
3) In your activity, implement the interface from this class. Then, in your activity, create an instance of this OnGlobalLayoutListener and set it as the listener for your listView
//make sure your class implements OnGlobalLayoutListenerWithScrollToBottom.OnScrollToBottomListener
listViewLayoutListener = new OnGlobalLayoutListenerWithScrollToBottom(this);
listView.getViewTreeObserver().addOnGlobalLayoutListener(listViewLayoutListener);
4) In your activity, before you make changes that will affect the size of list view, such as showing and hiding other views or adding stuff to the listview, simply let the layout listener know to scroll at the next opportunity
listViewLayoutListener.scrollToBottomAtNextOpportunity();
You might achieve this with setSelectionFromTop() and by overriding onSizeChanged() in a custom listview. In your layout, you should have a RelativeLayout has a parent container and place the listview above the edittext.
By creating your own listview and overriding onSizeChange(), you will be able to get the last visible item's position before the listview resizing and get its new height, in order to finally set the "previous" position of the list with an offset of its height.
How it works: Your list will place the previous last visible item at its top and you will add the pixels to scroll it at its bottom, just above your edittext.
To override the method and display it with an offset, do as follows:
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// get last visible item's position before resizing
int lastPosition = super.getLastVisiblePosition();
// call the super method to resize the listview
super.onSizeChanged(w, h, oldw, oldh);
// after resizing, show the last visible item at the bottom of new listview's height
super.setSelectionFromTop(lastPosition, (h - lastItemHeight));
}
lastItemHeight is a little workaround, because I didn't find how to get the last item's height before that onSizeChanged is called. Then, in the case of your listview contains many types of items (without the same height), I prefer to get the selected height when an event occurs, just before the SoftKeyboard opens up.
So in the custom listview, you have this global variable:
int lastItemHeight = 0;
And in the activity (or fragment, whatever), you update this value in OnClickListener:
edittext.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// set a new Thread
listview.post(new Runnable() {
#Override
public void run() {
// get last visible position of items
int lastPosition = listview.getLastVisiblePosition() - 1;
// if the view's last child can be retrieved
if ( listview.getChildAt(lastPosition) != null ) {
// update the height of the last child in custom listview
listview.lastItemHeight = listview.getChildAt(lastPosition).getHeight();
}
}
});
}
});
Note: there is another possible solution but you have to set android:stackFromBottom="true" on the listview, which stackes its content from the bottom. Instead, this solution here can display a specific item without forcing the content to start from the bottom, with the default listview's behaviour.
Second note: (just in case) don't forget to add android:windowSoftInputMode="adjustResize" in the manifest.
You should add this attribute in the manifest for your activity and pick the correct value for it (probably you will pick "adjustResize"):
<activity android:name="package.yourActivity" android:windowSoftInputMode="adjustResize"/>
I need to check on a button click if there is a drawing associated with the list or if its "invisible". I am doing the check by seeing if the source of the drawing is #drawable/invisible or something else. If its something else then change it to invisible, if invisible then change it to a color etc...
lv.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View listview, int position,
long arg3) {
ImageView pincolor=(ImageView) listview.findViewById(R.id.ivimtrackingpin);
// here is where I want to check what the "source" is
if(pincolor.getResources().equals(R.drawable.invisible)
//do stuff
else
pincolor.setImageresource(R.drawable.invisible)
}
});
I don't want to just do setvisibility =invisible because there are different colors that each list can be and the switch function will go inside the if part. What method do I use to determine the imageviews source?
Thanks
Maybe you can make use of the ImageView's getDrawable() Method.
/**
* Return the view's drawable, or null if no drawable has been assigned.
*/
public Drawable getDrawable ()
like this:
ImageView pincolor=(ImageView) listview.findViewById(R.id.ivimtrackingpin);
Drawable drawable = pincolor.getDrawable();
if(drawable != null) {
//do stuff with the drawable
} else {
pincolor.setImageresource(R.drawable.invisible)
}
This will tell you if the view is invisible:
pincolor.getVisibility()==View.INVISIBLE