I have CustomView and it works ok.
Now i need to change some item color by code.
So here is the code i have:
CustomView cv = new CustomView(mContext);
cv.setItemColor(Color.parseColor("#e77400"));
inside of my customView i add method:
public void setItemColor(int color){
mItemColorDefault = color;
invalidate();
requestLayout();
}
but after this nothing happen and customView does not refresh...
Please, help to fix this.
Thanks!
There is no need to call requestLayout() unless the size of the CustomView is not changed. This method only relates to views positioning updates.
You must override the onDraw() method as it is the place when your view is drawn. The invalidate() method causes onDraw() to invoked.
Use the mItemColorDefault color to draw your view with it in onDraw().
Here is the example of custom view with onDraw() method overridden:
https://github.com/dawidgdanski/TicTacToe/blob/master/game/src/main/java/pl/dawidgdanski/tictactoe/game/view/TicTacToeView.java
Hope this helps somehow.
Related
By default, onDraw() isn't called for ViewGroup.
So I have a question: What happen when we set background drawable for the ViewGroup
onDraw() is inherited from View class since ViewGroup is subclass of View. So when you set Background on a ViewGroup, it works the same way as any other view. When you call setBackground on a view, it sets requestLayout flag to true and invalidates the view.
Also, Official documentation for View class states that:
If you set a background drawable for a View, then the View will draw
it before calling back to its onDraw() method.
You can see how it works in the source code of Android's View class
public void setBackgroundDrawable(Drawable d) {
...
{
requestLayout = true;
}
...
computeOpaqueFlags();
if (requestLayout) {
requestLayout();
}
mBackgroundSizeChanged = true;
invalidate(true);
}
If you look at documentation for invalidate(), you will find
public void invalidate () Invalidate the whole view. If the view is
visible, onDraw(android.graphics.Canvas) will be called at some point
in the future.
setBackgroundColor() and setBackgroundResource() use setBackgroundDrawable() internally so they work the same way.
So to sum it up, onDraw is called at some point in future when you do setBackground().
The event onDraw() is emitted every time the View need to be repainted cause some graphic changes inside.
Unfortunately if the View is hidden (invisible) this event is not emitted since, obviously, there is no need to repaind anything. However I would to know if there is some trick to "cheat" the View to emit the onDraw() event and redraw itself exactly like it would really showed inside the screen.
Basically I need to capture screenshot status of a View component in all its changes but whitout show it (running it in background).
I guess it would be very hard to get such result but, just in case, I'll try to ask.
Thank you
I believe a View's visibility is checked by its parent and not the View itself. You can pass in a Canvas backed by a Bitmap straight in to View#draw(Canvas canvas) and it will draw itself on to the Bitmap. However, the based on the source code of View#setVisibility(), the View's background will still be invisible.
public void setVisibility(int visibility) {
setFlags(visibility, VISIBILITY_MASK);
if (mBGDrawable != null) mBGDrawable.setVisible(visibility == VISIBLE, false);
}
Everything else should appear in the View as is (unless it's children are also set to invisible of course).
EDIT:
Converting a view to Bitmap without displaying it in Android?
There are examples there on how to do that.
public static Bitmap getBitmapFromView(View view) {
Bitmap returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(),Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(returnedBitmap);
view.draw(canvas);
return returnedBitmap;
}
EDIT 2:
Since setVisibility() is not part of the View, you could override it and simply not set the View to be invisible. Something like:
boolean isInvisible = false;
#Override
public void setVisibility(int visibility) {
if (visibility == View.INVISIBLE) {
invisible = true;
} else {
invisible = false;
super.setVisibility();
}
}
#Override
public void onDraw(Canvas canvas) {
// change state code
if (!invisible) {
// draw code
super.onDraw(canvas);
}
}
#Override
public void draw(Canvas canvas) {
if (!invisible) {
// draw code
super.draw(canvas);
}
}
I have no idea what side-effects this would cause so be extremely careful and weary. Perhaps someone else would have a better solution. Another solution is you can simply call onDraw() on a different canvas whenever you want to draw it. This would require you to create a super class that is the parent layout View of the View you want to draw. Then in the parent's onDraw() method, call the child's onDraw() method separately if it's visibility is set to INVISIBLE.
If someone is interested I managed to solve this problem by override the invalidate() method. Instead of onDraw() that is called by the system only if the view is currently visible the invalidate() function is called "internally" and can be used to check if the view need to be reapinted in the same way.
I want to create skew animation for a View in android.
So, I have rectangular view (this is normal/start state), at the end it should looks like this:
I can do such a thing with android.view.animation package using Transformation of TYPE_MATRIX. So I can create Matrix and use preSkew method, apply this Matrix to my custom animation and then start this animation on a view. So this is OK.
BUT
The problem is I want to do this with ObjectAnimator.
Because using android.view.animation package is not recommended to use.
But I can't get the solution for this problem with ObjectAnimator class.
If I have ImageView, I can use method setImageMatrix for ObjectAnimator (and also create custom MatrixEvaluator to evaluate corresponding matrices for each factor),
but I want to get solution for this problem with a View class, not for some subclass of it.
And the main reason is, that TextView, for example, doesn't have public method like setMatrix, and I want to get the solution for TextView too. So get the solution for base View class is the main desire.
There is another solution: create custom, for example, SkewTextView, in which onDraw method we use canvas.skew method.
But this is worse solution even than using android.view.animation package, because you need to create wrappers for any View subclass you want to skew.
So, I don't know, how I can skew View with a ObjectAnimator (as View class doesn't have public methods like setSkew or setMatrix).
How would you solve this problem?
Have you any idea of how to solve this problem?
Is there a solution for this problem with ObjectAnimator?
Any help (or even thoughts) is greatly appreciated
Thanks
Well without subclassing this might be a bit tricky. My main idea is to use TimeAnimator, which will provide you time callbacks in conjunction with Camera (which can use Matrix transformations). Or you can use TimeAnimator and make a Bitmap from the View you want to skew, make the original View invisible, and draw the Bitmap on each TimeAnimator step applying a Matrix to it. But I'm not sure if this is the optimal way to do that, since you will have to create a new Bitmap on each frame
EDIT: No, Camera approach is not the way to do that as it is stated in comments below
I created a skew animation using Android Property Animation APIs in my project (GitHub Link).
What I did:
Created a custom view (SkewView) and added a SKEW_X property to it.
public class SkewView extends ImageView {
private static final String TAG = "SkewView";
public static final Property SKEW_X
= new FloatProperty("skewX") {
#Override
public void setValue(SkewView object, float value) {
object.setSkewX(value);
}
#Override
public Float get(SkewView object) {
return object.getSkewX();
}
};
private float mSkewX;
// ...
public float getSkewX() {
return mSkewX;
}
public void setSkewX(float skewX) {
mSkewX = skewX;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
if (mSkewX != 0) {
canvas.skew((float) (mSkewX * Math.PI / 180.0f), 0);
}
super.onDraw(canvas);
}
}
Used ObjectAnimator to animate this property.
ObjectAnimator skewAnimator = ObjectAnimator.ofFloat(mTarget, SkewView.SKEW_X, 30);
My project actually has quite a few lines of code right now, so I'll save you by only including here what matters. I hope it's enough information to make the issue clear.
I have two main classes: a 'GraphView' class, and then the main Activity's code. Within GraphView, I've created a function which, essentially, draws a rectangle on a canvas. It's called drawPixel. In GraphView's onDraw method, I call drawPixel a bunch of times, and it draws rectangles to the screen. Now, in the main code, I've programmatically created a layout and a button. What I want is that instead of calling drawPixel in GraphView's onDraw method, I want to draw those rectangles when I click a button. I tried this by doing:
someButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Canvas canvas = new Canvas();
// TODO Auto-generated method stub
for (int i=1; i<50; i++) {
someGraphView.drawPixel(canvas, i, i);
}
}
});
It didn't work. The rectangles draw correctly when i call then via onDraw(), but they don't draw at all when I call them from inside a setOnClickListener method. Does anyone know what I'm doing wrong?
Once that's written call invalidate() on your View.
I want to make a custom View so I extended the View class and override the onDraw(Canvas canvas) method.
The problems is, I found out that the method is never stopped being called.
well it seems that calling View.invalidate on a different View causes this view to redraw to.
I can't post the code in here so I try to describe only the relevant parts.
in the activity I create a FrameLayout m_mainLayout which is the one I finally pass to setContentView() method.
I add different Views and Layouts to m_mainLayout, one of them is GameView m_gameView which extends View and a GameFrameView which extends RelativeLayout and to this layout I add the View in question.
now, I constantly call (every ~100 ms) m_gameView.invalidate().
how does it cause other views to be redrawn ?
what do I need to do to stop this?
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas); <-- add this
int width = canvas.getWidth();
int height = canvas.getHeight();
Log.i("AttackDialogView", "onDraw ");
}