public class MainActivity extends Activity {
LinearLayout rotator;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rotator = (LinearLayout) findViewById(R.id.rotator);
ObjectAnimator rotation = ObjectAnimator.ofFloat(rotator, "rotationY", 0, 360);
rotation.setDuration(3000);
rotation.start();
}
}
I've got above code, which is rotating View around Y axis. Problem is, that the perspective seems to be too "strong" - the edge of view that is in foreground becomes too big and the edge in background becomes too small. Is there any possibility to "lower down" the perspecitve factor?
int distance = 1900;
float scale = getResources().getDisplayMetrics().density;
rotator.setCameraDistance(distance * scale);
So this is the solution for all screen densities.
Related
My question is about difference in setting the coordinates of the center a circle using the half of the view and directly. My device is 240 * 320 and when I use the getWidht()/2 and the getHeight() methods to draw a circle in center of the screen I am successful. But when I use the 120 value instead the getWidth/2 and the 160 value instead the getHight()/2 , I can not draw the circle in center of the screen. while I think the getWidth()/2 value is equal to the 120 value and the getHeight()/2 value is equal to the 160 value.
public class MainActivity extends Activity {
RelativeLayout relativeLayout;
C c;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
relativeLayout = (RelativeLayout) findViewById(R.id.re);
c = new C(getApplicationContext());
relativeLayout.addView(c);
}
}
class C extends View {
Paint paint;
C(Context context) {
super(context);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
paint.setAntiAlias(true);
paint.setColor(Color.RED);
canvas.drawCircle(120,160,20,paint);//this is not in the center of the screen.
canvas.drawCircle(getWidth/2, getHeight/2, 20 , paint);// But this is in center of the screen
}
}
Did you print the getWidth and getHeight? It maybe not 160 and 120, because it according to your views size, sometime the size it will reduce the status bar on some Android device...
I solved my problem. because the relativeLayout object has padding attribute. I should remove the padding attributes from the relativeLayout object. For more information please see here.
I am planning to perform a Rotating Animation on a two directional scroll view (see link). I have got the effect of the 2 directional scroll view, but now when i perform a Filp3D Type of animation (see link) i am getting a rotating window !
i actually wanted to perform a rotation around x-axis animation and then perform successive animation.
My Code is :
public class MainActivity extends Activity {
ScrollView sv;
WScrollView hsv;
Animation anim;
RelativeLayout rl;
Button b1,b2,b3;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/*BIDIRECTIONAL SCROLLVIEW*/
sv = new ScrollView(this);
hsv = new WScrollView(this);
hsv.sv = sv;
/*END OF BIDIRECTIONAL SCROLLVIEW*/
rl = new RelativeLayout(this);
rl.setBackgroundResource(R.drawable.interactivemap);
sv.addView(rl, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
hsv.addView(sv, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT /*or FILL_PARENT if API < 8*/));
setContentView(hsv);
Window window = getWindow();
window.setLayout(0, LayoutParams.WRAP_CONTENT);
/* Animation Effects : Stage I */
applyRotation(0, 45);
/* Animation Effects : Stage II */
/* Still to perform ! */
}
private void applyRotation(final float start, final float end) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
final float centerX = hsv.getWidth() / 2.0f + hsv.getLeft();
final float centerY = hsv.getHeight() / 2.0f + hsv.getTop();
Log.e("center-x center-y ",centerX+" "+centerY+"found");
final Flip3dAnimation rotation = new Flip3dAnimation(start, end, centerX, centerY);
rotation.setDuration(2000);
rotation.setFillAfter(true);
rotation.setInterpolator(new LinearInterpolator());
hsv.startAnimation(rotation);
}
}, 10);
}
}
Output :
1) The output is sometimes an animation around a different axis and then it becoming invisible, as if i have not put any setFillAfter(true), which happens to present in the Flip3dAnimation Class as shown in the two directional scroll view link.
2) The Animation comes and persists but only the original window is rotated in the 3d space, as if a card has flip 45 degrees !
I need the second Output with any window restrictions, as i have used a scroll view (2d), i want to be visible like a 2d plane as in a game like AOE (Age of Empires, seriously, people play games :D), or for non-games, a open 2d surface.
Please guide me for achieving the same, also please direct me to some source code which performs complex 2d animations for API-8 or 9.
I'm wondering how to measure the dimensions of a view. In my case it is aan Absolute Layout. I've read the answers concerning those questions but I still don't get it.
This is my code:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
AbsoluteLayout layoutbase = (AbsoluteLayout) findViewById(R.id.layoutbase);
drawOval();
}
public void drawOval(){ //, int screenWidth, int screenHeight){
AbsoluteLayout layoutbase = (AbsoluteLayout) findViewById(R.id.layoutbase);
int screenWidth = layoutbase.getWidth();
int screenHeight = layoutbase.getHeight();
Log.i("MyActivity", "screenWidth: " + screenWidth + ", screenHeight: " +screenHeight);
Coordinates c = new Coordinates(BUTTONSIZE,screenWidth,screenHeight);
...some code ...
((ViewGroup) layoutbase ).addView(mybutton, new AbsoluteLayout.LayoutParams(BUTTONSIZE, BUTTONSIZE, c.mX, c.mY));
mybutton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showText(mybutton);
}
});
}
public void showText(View button){
int x = findViewById(LAYOUT).getWidth();
int y = findViewById(LAYOUT).getHeight();
Toast message = Toast.makeText(this, "x: " + x , Toast.LENGTH_SHORT);
message.show();
}
The getWidth() command works great in showText() but it does not in drawOval(). I know it looks a bit different there but I also used the int x = findViewById(LAYOUT).getWidth(); version in drawOval(), and x/y are always 0. I don't really understand why there seems to be no width/height at that earlier point. Even if I actually draw a Button on the Absolute Layout, getWidth() returns 0. Oviously I want to measure the sizes in drawOval().
I think will help you.
LinearLayout headerLayout = (LinearLayout)findviewbyid(R.id.headerLayout);
ViewTreeObserver observer = headerLayout .getViewTreeObserver();
observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// TODO Auto-generated method stub
int headerLayoutHeight= headerLayout.getHeight();
int headerLayoutWidth = headerLayout.getWidth();
headerLayout .getViewTreeObserver().removeGlobalOnLayoutListener(
this);
}
});
}
getWidth() is giving you 0 because onCreate is called before layout actually happens. Due to views being able to have dynamic positions and sizes based on attributes or other elements (fill_parent for example) there's not a fixed size for any given view or layout. At runtime there is a point in time (actually it can happen repeatedly depending on many factors) where everything is actually measured and laid out. If you really need the height and width, you'll have to get them later as you've discovered.
This specially deal with Dimensions so
Display display = getWindowManager().getDefaultDisplay();
int width = display.getWidth();
int height = display.getHeight();
This may help you in managing dimensions.
Note: This returns the display dimensions in pixels - as expected. But the getWidth() and getHeight() methods are deprecated. Instead you can use:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
as also Martin Koubek suggested.
If your goal is to simply draw an oval on the screen, then consider creating your own custom View rather than messing around with AbsoluteLayout. Your custom View must override onDraw(android.graphics.Canvas), which will be called when the view should render its content.
Here is some extremely simple sample code that might help get you started:
public class MainActivity extends Activity {
private final Paint mPaint = new Paint();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new SampleView(this));
}
// create a nested custom view class that can draw an oval. if the
// "SampleView" is not specific to the Activity, put the class in
// a new file called "SampleView.java" and make the class public
// and non-static so that other Activities can use it.
private static class SampleView extends View {
public SampleView(Context context) {
super(context);
setFocusable(true);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.CYAN);
// smoothen edges
mPaint.setAntiAlias(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(4.5f);
// set alpha value (opacity)
mPaint.setAlpha(0x80);
// draw oval on canvas
canvas.drawOval(new RectF(50, 50, 20, 40), mPaint);
}
}
}
This give you screen resolution:
WindowManager wm = (WindowManager)context.getSystemService(context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point outSize = new Point();
display.getSize(outSize);
kabuko's answer is correct, but could be a little more clear, so let me clarify.
getWidth() and getHeight() are (correctly) giving you 0 because they have not been drawn in the layout when you call them. try calling the two methods on the button after addView() (after the view has been drawn and is present in the layout) and see if that gives you the expected result.
See this post for more information.
I am very new to Android and I am having problems figuring out how to layout views within a RelativeLayout programmatically. What I want to do is create 4 circles (child views) with a certain radius (say 50px) in the center of the RelativeLayout container, so it would look like I have an imaginary square in the center of the RelativeLayout and each vertex is the center for one of the circles.
I am able to draw the circle in the view; that is simple enough :)
class CircleView extends View {
...
protected void onDraw(Canvas canvas) {
// draw circle on canvas
}
}
What I cannot figure out is how to layout the views. It seems to draw them on top of each other, even though I am setting LayoutParams and an Id for each of the child views.
class Circles extends RelativeLayout {
public Circles(Context c) {
super(c);
addChildViews();
}
...
private void addChildViews() {
final Context c = getContext();
final CircleView v0 = new CircleView(c);
v0.setId(0);
final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.LEFT_OF, 1);
params.addRule(RelativeLayout.ABOVE, 2);
v0.setLayoutParams(params);
addView(v0);
....
// and so on, with relative layout params for other 3 views
}
}
Can somebody put me on the right track please? I also don't know if I am not calling addChildViews at the right time in the drawing cycle, and if this is what is leading to them being drawn on top of each other. Many thanks for any help.
Two things
1)The default action of a View is to fill its parent, so by applying (LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT) as your LayoutParams, you're creating four views with heights and widths the size of your parent layout (presumably the screen), so you'd only see one as the others would be positioned offscreen.
To fix this, either set the size you want the circles to be as your LayoutParms,
float dpi = getResources().getDisplayMetrics().density;
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams((int)(50.0f * dpi), (int)(50.0f * dpi));
or you could override the onMeasure(int x, int y) method in your Circle View like so
#Override
public void onMeasure(int x, int y) {
float dpi = getResources().getDisplayMetrics().density;
setMeasuredDimension((int)(50.0f * dpi), (int)(50.0f * dpi));
}
2) Don't set your View id to 0...I can't remember if it's system reserved or what, but it doesn't play nice.
Additionally, if you want all the circles centered in your Circles, you'll want to set its gravity to center like so.
public class Circles extends RelativeLayout {
public Circles (Context ctx) {
super(ctx);
this.setGravity(Gravity.CENTER);
addViewChildren();
}
This will center all of the Circles children, giving you the desired result.
I want to rotate my own FrameLayout in 3d in android. Do i have to use GlSurfaceView class. I am new in computer graphics but know the theory behind the rotations and translations. In order to make 3d opengl rotations we do the followings generally.
In activity class we create a GLSurfaceView object and set its renderer. Renderer object is created from a class which implements GlSurfaceView.Renderer interface.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GLSurfaceView view = new GLSurfaceView(this);
view.setRenderer(new OpenGLRenderer());
setContentView(view);
}
In our Renderer class we make the drawings, rotations and translations with following methods
// Called when the surface is created or recreated.
public void onSurfaceCreated(GL10 gl, EGLConfig config)
// Called to draw the current frame.
public void onDrawFrame(GL10 gl)
// Called when the surface changed size.
public void onSurfaceChanged(GL10 gl, int width, int height)
However i have a custom framelayout which is declared as
public class RotatedMapView extends FrameLayout
I want to make this :
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
RotatedMapView view = new RotatedMapView (this);
view.setRenderer(new OpenGLRenderer());
setContentView(view);
}
But i can't, because setRenderer is special for GlSurfaceView. I am now browsing the GlSurfaceView.java source code in order to adapt it to my design. The link i found for GlSurfaceVÄ°ew.java is http://code.google.com/p/apps-for-android/source/browse/trunk/SpriteMethodTest/src/com/android/spritemethodtest/GLSurfaceView.java?r=150
The source is too long. In fact I am not lazy to read it but i want to be sure whether or not i am in correct way.
Now i am looking at animations which i have never used. In api demos there is a rotation example over y axis. I want to make rotation over x. It is succesful for negative angles but in positive direction it disappears the view. The function is below.
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save();
if (mReverse) {
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
camera.rotateY(degrees);
`camera.rotateX(degrees); //i want to do this it works for negative but not` //positive angles
camera.getMatrix(matrix);
camera.restore();
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
}
Framelayouts (and anything extending View) are designed to be drawn on a Canvas element in 2D. It is not possible to draw these using openGL. If you want to draw a GUI in 3D/GL then you will have to code that up from scratch or find a library which has already done this. I'm sure there are a few out there but I haven't had the need for one yet.
You can get some fake looking 3D effects on views by using scale animations, though these will only work if the animation is done fast so the user doesn't notice. This probably isn't what you are after.
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:fromXScale="1.0" android:toXScale="0.0"
android:fromYScale="1.0" android:toYScale="1.0"
android:pivotX="50%" android:pivotY="0%"
android:duration="#android:integer/config_shortAnimTime"
/>