I am trying to use the RotationAnimation to move an ImageButton. I have extended ImageButton to override onAnimationEnd to avoid the screen flicker at the end of the animation, and would like to update the position of the actual button [since the animation is just a superficial move]. How can I determine the exact coordinates of the button at the end of the animation? Attached is some of my code..
public class HomeNavigationButton extends ImageButton {
public HomeNavigationButton(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public HomeNavigationButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HomeNavigationButton(Context context) {
super(context);
}
#Override
protected void onAnimationEnd() {
super.onAnimationEnd();
int l = ?
int t = ?
int r = ?
int b = ?
this.layout(l,t,r,b);
}
The position of the button animation? I would go out on a limb and guess you can't. Animations are interesting. They're not "real". Think of them as a mirage. Try this. Rotate the image VERY slowly. If the image is a rectangle, when the image is about 45 degrees, click where the image used to be, but is no long. You'll actually register a click, because the image isn't actually being rotate in real coordinates.
I would consider actually animating the button like a game sprite, or do some trial and error with the animation and set values manually. If you do the second one, make sure you dynamically convert to DIP coordinates rather than raw ints.
Related
I must get upside down view w/o moving the System menu. So I do:
getWindow().getDecorView().getRootView().setRotation(180);
But all child buttons get onTouch event not when they being touched, but when I touch the areas where they would be without rotation.
How can I fix the problem?
Got solution without translation matrix and such... Just create a new Layout class like this:
public class RotatableView extends FrameLayout {
public RotatableView(Context context) {
this(context, null);
}
public RotatableView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
setUpsideDown();
}
private void setUpsideDown() {
this.setRotation(180);
}
}
and use it for your layouts
I have a custom built circular progress bar used for a seconds counter on a clock, which I'd like to flip, so that the clock is counting counter-clockwise.
Searching here for a solution, I found this:
Right to Left ProgressBar?
Which obviously works for a horizontal progress bar, but I can't simply rotate it 180 degrees, since that will just move the clock 180 degrees and it will still be ticking clockwise.
Is there any other way to mirror a ProgressBar, or any View?
Edit:
Just found "android:rotationY" and the programmatic equivalent, but this ideally needs to be for 2.2 and above..
I was able to flip ProgressBar simply with attribute scaleX in XML:
android:scaleX="-1"
This works for other View as well.
Extend ProgressBar in the same way you would for a horizontal progress bar, but in the onDraw method, flip the canvas rather than rotate it:
public class InverseProgressBar extends ProgressBar {
public InverseProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public InverseProgressBar(Context context, AttributeSet attrs) {
super(context, attrs);
}
public InverseProgressBar(Context context) {
super(context);
}
#Override
protected synchronized void onDraw(Canvas canvas) {
canvas.scale(-1f, 1f, super.getWidth() * 0.5f, super.getHeight() * 0.5f);
super.onDraw(canvas);
}
}
Yes. In newer versions of material design library, the circular progress bar can be mirrored:
in the layout with this attribute
app:indicatorDirectionCircular
or programmatically with this method
setIndicatorDirection()
Refer here for more info.
I'm looking to replicate the following within my application:
As you can see, its basically a button which increases/decreases the value of the text view contained within it. This button will have three visual states -> unpressed, decrease and increase (as seen in the image above, the user taps the increase arrows and the button appears pressed in on that side)
Here are my 3 button states currently:
As you can see, the problem I have is being able to correctly skew/rotate the text view so it looks visually correct and appears slanted along with the button when its being increased or decreased.
I have tried two different approaches so far:
Create a custom text view class which overrides the onDraw() method to skew the canvas:
#Override
public void onDraw(Canvas canvas) {
canvas.save();
canvas.skew(0.2f, 0f);
super.onDraw(canvas);
canvas.restore();
}
Integrate the Rotate3dAnimation class (source here) and used many different variations to get the desired result such as:
Rotate3dAnimation skew = new Rotate3dAnimation(
30, 0, centerX, centerY, 0, false);
txtAmount.startAnimation(skew);
Unfortunately, I'm not quite getting the exact result that mirrors the first image above. I'm getting confused with setting values with the Z-axis, skew, rotate etc.
I'd greatly appreciate any help from anyone who has experience with this stuff. Thanks in advance
Well I even tried and I came up with something like this:
public class DemoActivity extends TextView {
Context context;
String firstText = "$120.00";
public DemoActivity(Context context)
{
super(context);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setText(firstText);
setTextSize(30);
canvas.skew(1.0f, 0.3f); //you need to change values over here
Rotate3dAnimation skew = new Rotate3dAnimation(
-20, 30,200, 200, 0, false); //here too
startAnimation(skew);
}
}
I got an output as:
I guess changing the values by trial and error can solve your problem.
Hope it helps.
Thanks to Parth Doshi answer. His answer need a little tweaking to run which I'm sharing here to save someone else time.
First create a class in src folder and write all of three constructors.
public class TextViewDemo extends TextView {
Context context;
String text = "TESTING 3DX TOOLS";
public TextViewDemo(Context context) {
super(context);
this.context = context;
}
public TextViewDemo(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public TextViewDemo(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
setText(text);
setTextSize(30);
canvas.skew(0.5f, 1.0f); // you need to change values over here
Rotate3dAnimation skew = new Rotate3dAnimation(-50, 30, 0, 0, 0,
false); // here too
startAnimation(skew);
}
}
In you res/layout/my_layout.xml file you can add a tag of your custom made TextView.
<com.yourpackage.name.TextViewDemo
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="Hello World"
<!-- All parameters and value shall remain same -->
/>
Like any other view, you can create an instance of TextViewDemo in your onCreate() method
TextViewDemo txtDemo = (TextViewDemo) findViewById(R.id.name);
Regards
I want to be able to mirror my app so it can be viewed in the windshield of a vehicle.
My XML has several nested LinearLayouts, TextViews and ImageViews. Currently I'm transforming each one and although it is mirrored, the structure of the elements is not (what was at the top is now at the bottom).
I've been looking for days and so far have tried a couple of approaches that have failed.
An animation that uses a matrix to flip on the X axis kind of works, except that it either reverts back or it stays and doesn't update, which is no good for interacting with the app.
I just tried to create a custom LinearLayout extending the parent one, hoping that I could apply a Matrix in its onDraw() method but that gives me a blank screen (I had to set setWillNotDraw(false); to hit the onDraw()).
Well eventually I found a solution that works well for me (so far it's caused no issues for users).
My solution was to override dispatchDraw to scale the canvas in my custom LinearLayout. Then I just needed to flip the touch events by overriding dispatchTouchEvent:
public class CustomContainer extends LinearLayout {
public CustomContainer(Context context) {
super(context);
this.setWillNotDraw(false);
}
public CustomContainer(Context context, AttributeSet attrs) {
super(context, attrs);
this.setWillNotDraw(false);
}
public CustomContainer(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setWillNotDraw(false);
}
#Override
protected void dispatchDraw(Canvas canvas) {
canvas.save(Canvas.MATRIX_SAVE_FLAG);
// Flip the view canvas
if (MyHUDActivity.mHUDMode) canvas.scale(1,-1, getWidth(), getHeight()/2f);
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public boolean dispatchTouchEvent(MotionEvent event) {
// If in HUD mode then flip the touch zones
if (MyHUDActivity.mHUDMode) event.setLocation(event.getX(), getHeight()-event.getY());
return super.dispatchTouchEvent(event);
}
}
You can use the new Animation api to deal with reverting back after the horizontal flip.
long time reader, first time asker so please be gently ;)
I have an Android code that displays around 10 pictures in second on ImageView.
(calling setImageBitmap on ImageView to set new bitmap)
This causes display lags so I'm trying to speed it as much as I can.
I found that (with traceview) that app spend a lot of time on methods:
ViewRoot.performTraversals
View.measure
FrameLayout.onmeasure
ViewGrou.measureChildWithMargins
I suspecting on ImageView measuring so i have create CustomImageView and overide onMeasure just to call super method and write sysout.
It seems that after every setImageBitmap onmeasure is called 3 times.
Bitmaps are allways of the same size so there is no change. Actually it can be change from time to time when image source is changed but that should be remeasured only then.
What can I change, overide, do to eliminite this measurement impact on application speed?
If you need further information tell me and I will provide it.
Sample code
final Bitmap bitmapScaled = Bitmap.createScaledBitmap(bitmap2, width, height, false);
imageView2.setScaleType(ScaleType.CENTER_INSIDE);
if (setSize) {
setSize(imageView2, width, height);
}
imageView2.setImageBitmap(bitmapScaled);
Method that I change to make it work faster (possibly not safe?!)
boolean layout=true;
int noL=1;
#Override
public void requestLayout() {
if (layout){
super.requestLayout();
if (noL>10){
layout=false;
}else{
noL++;
}
}
}
When I had a similar problem I did the following:
public class ImageViewEx extends ImageView{
private boolean makeRequest;
public ImageViewEx(Context context){
super(context);makeRequest=true;
}
public ImageViewEx(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ImageViewEx(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
makeRequest=true;
}
public void setImageBitmapNoRequestLayout(Bitmap bitmap) {
makeRequest = false;
setImageBitmap(bitmap);
makeRequest = true;
}
#Override public void requestLayout(){
if(makeRequest)super.requestLayout();
}
}
Now changing the bitmap with setImageBitmapNoRequestLayout(...) does not call requestLayout().