How can I get the available height of the screen in Android? I need to the height minus the status bar / menu bar or any other decorations that might be on screen and I need it to work for all devices. Also, I need to know this in the onCreate function. I know this question has been asked before but I have already tried their solutions and none of them work. Here are some of the things I have tried:
This does not take into account the status bar / menu bar:
Display display = getWindowManager().getDefaultDisplay();
screenWidth = display.getWidth();
screenHeight = display.getHeight();
Neither does this:
Point size = new Point();
getWindowManager().getDefaultDisplay().getSize(size);
screenWidth = size.x;
screenHeight = size.y;
Nor this:
Point size = new Point();
getWindowManager().getDefaultDisplay().getRealSize(size);
screenWidth = size.x;
screenHeight = size.y;
This does not work:
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
// since SDK_INT = 1;
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
try
{
// used when 17 > SDK_INT >= 14; includes window decorations (statusbar bar/menu bar)
screenWidth = (Integer) Display.class.getMethod("getRawWidth").invoke(display);
screenHeight = (Integer) Display.class.getMethod("getRawHeight").invoke(display);
}
catch (Exception ignored)
{
// Do nothing
}
try
{
// used when SDK_INT >= 17; includes window decorations (statusbar bar/menu bar)
Point realSize = new Point();
Display.class.getMethod("getRealSize", Point.class).invoke(display, realSize);
screenWidth = realSize.x;
screenHeight = realSize.y;
}
catch (Exception ignored)
{
// Do nothing
}
I then used the following code to subtract the height of the status bar and menu bar from the screen height:
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
result = getResources().getDimensionPixelSize(resourceId);
screenHeight -= result;
result = 0;
if (screenHeight >= screenWidth)
resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
else
resourceId = getResources().getIdentifier("navigation_bar_height_landscape", "dimen", "android");
if (resourceId > 0)
result = getResources().getDimensionPixelSize(resourceId);
screenHeight -= result;
On API 17 it gives it correctly calculates the height of the status bar and menu bar in portrait but not in landscape. On API 10, it returns 0. I need it to work ideally on all devices or minimum API 10.
Have you tried doing your height calculations in onWindowFocusChanged of the Activity class? This eliminates API troubles by calculating what you really want, not messing with menu bars etc.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
View content = getWindow().findViewById(Window.ID_ANDROID_CONTENT);
screenHeight=content.getHeight();
}
Here is how I managed to get the correct screen dimensions for all devices:
public class MainActivity extends Activity
{
static int ScreenWidth;
static int ScreenHeight;
static int ScreenWidthLandscape;
static int ScreenHeightLandscape;
private RelativeLayout layout;
private RelativeLayout.LayoutParams params;
private View top;
private View bottom;
#SuppressWarnings("deprecation")
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
layout = new RelativeLayout(this);
top = new View(this);
bottom = new View(this);
RelativeLayout.LayoutParams viewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1);
viewParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
top.setLayoutParams(viewParams);
viewParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1);
viewParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
bottom.setLayoutParams(viewParams);
layout.addView(top);
layout.addView(bottom);
setContentView(layout);
final Intent intent = new Intent(this, myPackage.learnSpanishVerbs.Start.class);
final View view = getWindow().getDecorView().getRootView();
ViewTreeObserver vto = view.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener()
{
#Override
public void onGlobalLayout()
{
int topLoc[] = new int[2];
top.getLocationOnScreen(topLoc);
int BottomLoc[] = new int[2];
bottom.getLocationOnScreen(BottomLoc);
boolean portrait = getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE;
if (portrait)
{
ScreenWidth = top.getWidth();
ScreenHeight = BottomLoc[1] - topLoc[1];
}
else
{
ScreenWidthLandscape = top.getWidth();
ScreenHeightLandscape = BottomLoc[1] - topLoc[1];
}
if (Build.VERSION.SDK_INT < 16)
view.getViewTreeObserver().removeGlobalOnLayoutListener(this);
else
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
startActivity(intent);
finish();
}
});
}
}
The best solution I have managed to come up with is this:
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
TypedValue tv = new TypedValue();
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
{
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
screenHeight -= TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
screenHeight -= getResources().getDimensionPixelSize(resourceId);
I have tested it on API 7 - 17. Unfortunately, on API 13 there is extra space at bottom both horizontally and vertically and on API 10, 8, and 7 there is not enough space at the bottom both horizontally and vertically. (I have not tested on obsolete APIs).
Related
I want to transfer motionevent to dialog from view onTouchListener
I tried AlertDialog.dispatchTouchEvent but this doesnt work, event just stops at my view and dont go any further.
Code:
final View v = new View(this);
v.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.format = PixelFormat.TRANSLUCENT;
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
params.packageName = getPackageName();
getWindowManager().addView(v,params);
v.setOnTouchListener(new OnTouchListener() {
public boolean onTouch(View v,MotionEvent event) {
if(event.getAction()==MotionEvent.ACTION_UP) {
d.getButton(DialogInterface.BUTTON_NEGATIVE).setText(no);
d.getButton(DialogInterface.BUTTON_POSITIVE).setText(yes);
} else {
int[] pos = new int[2];
Button b = d.getButton(DialogInterface.BUTTON_NEGATIVE);
int w = b.getWidth();
int h = b.getHeight();
b.getLocationOnScreen(pos);
if(event.getRawX() < pos[0] + w && event.getRawX() > pos[0] && event.getRawY() < pos[1] + h && event.getRawY() > pos[1]) {
b.setText(yes);
d.getButton(DialogInterface.BUTTON_POSITIVE).setText(no);
} else {
b.setText(no);
d.getButton(DialogInterface.BUTTON_POSITIVE).setText(yes);
}
}
return d.dispatchTouchEvent(event);
//return false;
}
});
d - dialog that i want to transfer MotionEvent...
yes,no - Strings with text
I created the recyclerview with grid layout manager. When any one clicks on the image thumbnail the image should be expanded to full screen in Dialogfragment which has view pager with the animation from the thumb clicked.
I have tried the different solution but not worked. The animation directly applied from the styles working but how to define the dynamic runtime animation.
I had tried the following but not working exactly.
Any idea on how to achieve this thing??
MediaFragment.java
#Override
public void onItemClick(View v, int position) {
switch (v.getId()) {
case R.id.llItemContainer:
Bundle bundle = new Bundle();
bundle.putInt(Constant.KEY_CURRENT_ITEM, position);
dialogMediaProfileFragment = new DialogMediaProfileFragment();
dialogMediaProfileFragment.setArguments(bundle);
dialogMediaProfileFragment.show(getFragmentManager(), TAG);
zoomImageFromThumb(v).start();
break;
}
}
private Animator zoomImageFromThumb(final View thumbView) {
if (mCurrentAnimator != null) {
mCurrentAnimator.cancel();
}
startBounds = new Rect();
finalBounds = new Rect();
Point globalOffset = new Point();
thumbView.getGlobalVisibleRect(startBounds);
rvMediaPost.getGlobalVisibleRect(finalBounds, globalOffset);
startBounds.offset(-globalOffset.x, -globalOffset.y);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
if ((float) finalBounds.width() / finalBounds.height() > (float) startBounds
.width() / startBounds.height()) {
// Extend start bounds horizontally
startScale = (float) startBounds.height() / finalBounds.height();
float startWidth = startScale * finalBounds.width();
float deltaWidth = (startWidth - startBounds.width()) / 2;
startBounds.left -= deltaWidth;
startBounds.right += deltaWidth;
} else {
// Extend start bounds vertically
startScale = (float) startBounds.width() / finalBounds.width();
float startHeight = startScale * finalBounds.height();
float deltaHeight = (startHeight - startBounds.height()) / 2;
startBounds.top -= deltaHeight;
startBounds.bottom += deltaHeight;
}
setAlpha(thumbView, 1f);
//This shows the nullpointer exception
/*setPivotX(dialogMediaProfileFragment.getView(), 0f);
setPivotY(dialogMediaProfileFragment.getView(), 0f);*/
AnimatorSet set = new AnimatorSet();
set.play(
ObjectAnimator.ofFloat(dialogMediaProfileFragment, "translationX",
startBounds.left, finalBounds.left))
.with(ObjectAnimator.ofFloat(dialogMediaProfileFragment, "translationY",
startBounds.top, finalBounds.top))
.with(ObjectAnimator.ofFloat(dialogMediaProfileFragment, "scaleX",
startScale, 1f))
.with(ObjectAnimator.ofFloat(dialogMediaProfileFragment, "scaleY",
startScale, 1f));
set.setDuration(mShortAnimationDuration);
set.setInterpolator(new DecelerateInterpolator());
set.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
mCurrentAnimator = null;
}
#Override
public void onAnimationCancel(Animator animation) {
mCurrentAnimator = null;
}
});
return mCurrentAnimator = set;
}
private void setAlpha(View view, float alpha) {
view.setAlpha(alpha);
}
private void setPivotX(View view, float x) {
view.setPivotX(x);
}
private void setPivotY(View view, float y) {
view.setPivotY(y);
}
#Jaymin Panchal,
You have to implement customize Android Activity Transition animation.
Also you can refer this code snippet for more on about your requirement.
I have this animation activity for falling images. It works perfectly. What I would like to is change this, so I can call something like, startImageFallAnimation(), in another activity, and have it show over the current activity. I'd hate to have to add all this code to every activity I want to use it in. I experimented for a few hours, with no luck.
How can I accomplish this?
import com.tmp.animation.R;
public class FallAnimationActivity extends Activity {
// 100 = lots falling / 1000 = less falling
public int imageInterval = 100;
private int[] LEAVES = {
R.drawable.coin,
R.drawable.starsm,
//R.drawable.leaf_yellow,
//R.drawable.leaf_other,
};
private Rect mDisplaySize = new Rect();
private RelativeLayout mRootLayout;
private ArrayList<View> mAllImageViews = new ArrayList<View>();
private float mScale;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Display display = getWindowManager().getDefaultDisplay();
display.getRectSize(mDisplaySize);
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
mScale = metrics.density;
mRootLayout = (RelativeLayout) findViewById(R.id.main_layout);
new Timer().schedule(new ExeTimerTask(), 0, imageInterval);
}
public void create() {
setContentView(R.layout.main);
Display display = getWindowManager().getDefaultDisplay();
display.getRectSize(mDisplaySize);
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
mScale = metrics.density;
mRootLayout = (RelativeLayout) findViewById(R.id.main_layout);
new Timer().schedule(new ExeTimerTask(), 0, imageInterval);
}
public void startAnimation(final ImageView aniView) {
aniView.setPivotX(aniView.getWidth()/2);
aniView.setPivotY(aniView.getHeight()/2);
long delay = new Random().nextInt(Constants.MAX_DELAY);
final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(Constants.ANIM_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.setStartDelay(delay);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int angle = 50 + (int)(Math.random() * 101);
int movex = new Random().nextInt(mDisplaySize.right);
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = ((Float) (animation.getAnimatedValue())).floatValue();
aniView.setRotation(angle*value);
aniView.setTranslationX((movex-40)*value);
aniView.setTranslationY((mDisplaySize.bottom + (150*mScale))*value);
}
});
animator.start();
}
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int viewId = new Random().nextInt(LEAVES.length);
Drawable d = getResources().getDrawable(LEAVES[viewId]);
LayoutInflater inflate = LayoutInflater.from(FallAnimationActivity.this);
ImageView imageView = (ImageView) inflate.inflate(R.layout.ani_image_view, null);
imageView.setImageDrawable(d);
mRootLayout.addView(imageView);
mAllImageViews.add(imageView);
LayoutParams animationLayout = (LayoutParams) imageView.getLayoutParams();
animationLayout.setMargins(0, (int)(-150*mScale), 0, 0);
animationLayout.width = (int) (60*mScale);
animationLayout.height = (int) (60*mScale);
startAnimation(imageView);
}
};
private class ExeTimerTask extends TimerTask {
#Override
public void run() {
// we don't really use the message 'what' but we have to specify something.
mHandler.sendEmptyMessage(Constants.EMPTY_MESSAGE_WHAT);
}
}
}
EDIT- After lots of work, this is the best I've got, but I cant solve passing context into the handler, or passing the layout into the first method.
import com.tmp.animation.R;
public class FallPop {
private static final String TAG = FallPop.class.toString();
private static final FallPop INSTANCE = new FallPop();
private int[] LEAVES = {
R.drawable.leaf_green,
R.drawable.leaf_red,
R.drawable.leaf_yellow,
R.drawable.leaf_other,
};
private Rect mDisplaySize = new Rect();
private RelativeLayout mRootLayout;
private ArrayList<View> mAllImageViews = new ArrayList<View>();
private float mScale;
private FallPop(){
}
public static FallPop getInstance() {
return INSTANCE;
}
public Context context;
public Context context2;
int count = 0;
public void doAnim(Context context){
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
display.getRectSize(mDisplaySize);
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
mScale = metrics.density;
// FIX!!!
// mRootLayout = (RelativeLayout) findViewById(R.id.main_layout);
new Timer().schedule(new ExeTimerTask(), 0, 200);
}
public void startAnimation(final ImageView aniView) {
aniView.setPivotX(aniView.getWidth()/2);
aniView.setPivotY(aniView.getHeight()/2);
long delay = new Random().nextInt(Constants.MAX_DELAY);
final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(Constants.ANIM_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.setStartDelay(delay);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int angle = 50 + (int)(Math.random() * 101);
int movex = new Random().nextInt(mDisplaySize.right);
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = ((Float) (animation.getAnimatedValue())).floatValue();
aniView.setRotation(angle*value);
aniView.setTranslationX((movex-40)*value);
aniView.setTranslationY((mDisplaySize.bottom + (150*mScale))*value);
}
});
animator.start();
}
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int viewId = new Random().nextInt(LEAVES.length);
// Need some context here \/
Drawable d = ContextCompat.getDrawable(context, LEAVES[viewId]);
// Original line, also didnt work \/
//Drawable d = getResources().getDrawable(LEAVES[viewId]);
LayoutInflater inflate = LayoutInflater.from(context);
ImageView imageView = (ImageView) inflate.inflate(R.layout.ani_image_view, null);
imageView.setImageDrawable(d);
mRootLayout.addView(imageView);
mAllImageViews.add(imageView);
RelativeLayout.LayoutParams animationLayout = (RelativeLayout.LayoutParams) imageView.getLayoutParams();
animationLayout.setMargins(0, (int) (-150 * mScale), 0, 0);
animationLayout.width = (int) (60 * mScale);
animationLayout.height = (int) (60 * mScale);
startAnimation(imageView);
}
};
class ExeTimerTask extends TimerTask {
#Override
public void run() {
// we don't really use the message 'what' but we have to specify something.
mHandler.sendEmptyMessage(Constants.EMPTY_MESSAGE_WHAT);
}
}
}
Create a Java class with static method startImageFallAnimation(),where you will write all your animation code and just call the method wherever it is required
The quickest solution I can think of would be to make the target Activities extend this class and change the access level of the member variables in FallAnimationActivity to 'protected'. Depending on whether you need this in all/most Activities, I'd put the logic in a base class.
have context as a parameter in your util class
example:
public animation(Imageview imageview, Context mContext)
{
Animation slideLeft = AnimationUtils.loadAnimation(mContext, R.anim.slide_out_left);
imageview.startAnimation(slideLeft);
}
then in the activity you want to call it in do
// for activity
Utils.animation(Your image view, this)
//for fragment
Utils.animation(Your image view, getContext)
my utility class is called Utils, so you type whatever you named the class and call the method accordingly
I have pinch zooming for an image, however when I first load the app the whole of the image is not visible, only a portion. The image fills the width of the screen but there is white-space above and below it. Also when the image is scaled the image becomes very short. The aspect ratio should stay the same.
I would like to have the whole image visible when the app loads and then I want to be able to zoom out with two fingers where the image doesn't become smaller than the size of the screen, so that the screen is always full (the image is a map).
For zooming in, the image should scale beyond the width and height of the phone screen. That way I can pan across to view the map in detail.
Any help would be greatly appreciated. Related code is below.
My MainActivity code:
public class MainActivity extends Activity
{
private MapView image;
private Matrix matrix = new Matrix();
float mLastTouchX, mPosX;
float mLastTouchY, mPosY;
private ScaleGestureDetector mScaleDetector;
private float mScaleFactor = 1f;
private int mActivePointerId = MotionEvent.INVALID_POINTER_ID;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
image = (MapView)findViewById(R.id.imageView1);
mScaleDetector = new ScaleGestureDetector(MainActivity.this, new ScaleListener());
}
public void onDraw(Canvas canvas)
{
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings)
{
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public boolean onTouchEvent(MotionEvent event)
{
mScaleDetector.onTouchEvent(event);
final int action = MotionEventCompat.getActionMasked(event);
switch (action)
{
case MotionEvent.ACTION_DOWN:
{
final int pointerIndex = MotionEventCompat.getActionIndex(event);
final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex);
// Remember where we started (for dragging)
mLastTouchX = x;
mLastTouchY = y;
// Save the ID of this pointer (for dragging)
mActivePointerId = MotionEventCompat.getPointerId(event, 0);
break;
}
case MotionEvent.ACTION_MOVE:
{
// Find the index of the active pointer and fetch its position
final int pointerIndex =
MotionEventCompat.findPointerIndex(event, mActivePointerId);
final float x = MotionEventCompat.getX(event, pointerIndex);
final float y = MotionEventCompat.getY(event, pointerIndex);
// Calculate the distance moved
final float dx = x - mLastTouchX;
final float dy = y - mLastTouchY;
mPosX += dx;
mPosY += dy;
// Remember this touch position for the next move event
mLastTouchX = x;
mLastTouchY = y;
break;
}
case MotionEvent.ACTION_UP:
{
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_CANCEL:
{
mActivePointerId = MotionEvent.INVALID_POINTER_ID;
break;
}
case MotionEvent.ACTION_POINTER_UP:
{
final int pointerIndex = MotionEventCompat.getActionIndex(event);
final int pointerId = MotionEventCompat.getPointerId(event, pointerIndex);
if (pointerId == mActivePointerId)
{
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mLastTouchX = MotionEventCompat.getX(event, newPointerIndex);
mLastTouchY = MotionEventCompat.getY(event, newPointerIndex);
mActivePointerId = MotionEventCompat.getPointerId(event, newPointerIndex);
}
break;
}
}
image.setX(mPosX);
image.setY(mPosY);
return true;
}
private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
#Override
public boolean onScale(ScaleGestureDetector detector)
{
mScaleFactor *= detector.getScaleFactor();
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
matrix.setScale(mScaleFactor, mScaleFactor);
image.setImageMatrix(matrix);
return true;
}
}
}
Custom ImageView:
public class MapView extends ImageView
{
public MapView(final Context context, final AttributeSet attrs)
{
super(context, attrs);
}
public void scaleImage(int boundBoxInDp)
{
Drawable drawable = getDrawable();
Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();
int width = bitmap.getWidth();
int height = bitmap.getHeight();
float xScale = ((float) boundBoxInDp) / width;
float yScale = ((float) boundBoxInDp) / height;
float scale = (xScale <= yScale) ? xScale : yScale;
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
BitmapDrawable result = new BitmapDrawable(scaledBitmap);
width = scaledBitmap.getWidth();
height = scaledBitmap.getHeight();
// Apply the scaled bitmap
setImageDrawable(result);
// Now change ImageView's dimensions to match the scaled image
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)getLayoutParams();
params.width = width;
params.height = height;
setLayoutParams(params);
}
private int dpToPx(Context c, int dp)
{
float density = c.getResources().getDisplayMetrics().density;
return Math.round((float)dp * density);
}
#Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec)
{
final Drawable d = this.getDrawable();
if (d != null)
{
// ceil not round - avoid thin vertical gaps along the left/right edges
final int width = MeasureSpec.getSize(widthMeasureSpec);
final int height = (int) Math.ceil(width * (float) d.getIntrinsicHeight() / d.getIntrinsicWidth());
this.setMeasuredDimension(width, height);
}
else
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
Layout file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<com.kilobolt.framework.locationfinder.MapView
android:id="#+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="matrix"
android:src="#drawable/uea" />
</RelativeLayout>
I took a different approach to solve the problem of displaying a custom map. Instead of displaying a fixed sized image, I used Google Maps Javascript API v3 (https://developers.google.com/maps/documentation/javascript/examples/marker-simple).
I displayed this in a web view and created a reusable function in javascript to create custom markers.
If anyone comes across this issue, which appears to not to be well documented, give this map solution a try, and feel free to message me. Hope this helps.
I wonder if I can get a way to let video run via videoview in full screen?
I searched a lot and tried many ways such as:
Apply theme in manifest:
android:theme="#android:style/Theme.NoTitleBar.Fullscreen"
but that does not force the video to be in full screen.
Apply in activity itself:
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
also does not force the video to be in full screen.
The only way force video to full screen is:
<VideoView android:id="#+id/myvideoview"
android:layout_width="fill_parent"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_height="fill_parent">
</VideoView>
This way it results in full screen video but it stretches the video itself (elongated video) ,
I'm not applying this improper solution to my videoview, so is there is any way to do it without stretching the video?
Video Class:
public class Video extends Activity {
private VideoView myvid;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
myvid = (VideoView) findViewById(R.id.myvideoview);
myvid.setVideoURI(Uri.parse("android.resource://" + getPackageName()
+"/"+R.raw.video_1));
myvid.setMediaController(new MediaController(this));
myvid.requestFocus();
myvid.start();
}
}
main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<VideoView
android:id="#+id/myvideoview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</LinearLayout>
Like this you can set the properties of the video by yourself.
Use a SurfaceView (gives you more control on the view), set it to fill_parent to match the whole screen
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="fill_parent">
<SurfaceView
android:id="#+id/surfaceViewFrame"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center" >
</SurfaceView>
</Linearlayout>
then on your java code get the surface view and add your media player to it
surfaceViewFrame = (SurfaceView) findViewById(R.id.surfaceViewFrame);
player = new MediaPlayer();
player.setDisplay(holder);
set on your media player a onPreparedListener and manually calculate the desired size of the video, to fill the screen in the desired proportion avoiding stretching the video!
player.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// Adjust the size of the video
// so it fits on the screen
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = surfaceViewFrame.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
surfaceViewFrame.setLayoutParams(lp);
if (!player.isPlaying()) {
player.start();
}
}
});
I modified this from a tutorial for video streaming that I followed some time ago, can't find it right now to reference it, if someone does please add the link to the answer!
Hope it helps!
EDIT
Ok, so, if you want the video to occupy the whole screen and you don't want it to stretch you will end up with black stripes in the sides. In the code I posted we are finding out what is bigger, the video or the phone screen and fitting it the best way we can.
There you have my complete activity, streaming a video from a link. It's 100% functional. I can't tell you how to play a video from your own device because I don't know that. I'm sure you will find it in the documentation here or here.
public class VideoPlayer extends Activity implements Callback, OnPreparedListener, OnCompletionListener,
OnClickListener {
private SurfaceView surfaceViewFrame;
private static final String TAG = "VideoPlayer";
private SurfaceHolder holder;
private ProgressBar progressBarWait;
private ImageView pause;
private MediaPlayer player;
private Timer updateTimer;
String video_uri = "http://daily3gp.com/vids/familyguy_has_own_orbit.3gp";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.videosample);
pause = (ImageView) findViewById(R.id.imageViewPauseIndicator);
pause.setVisibility(View.GONE);
if (player != null) {
if (!player.isPlaying()) {
pause.setVisibility(View.VISIBLE);
}
}
surfaceViewFrame = (SurfaceView) findViewById(R.id.surfaceViewFrame);
surfaceViewFrame.setOnClickListener(this);
surfaceViewFrame.setClickable(false);
progressBarWait = (ProgressBar) findViewById(R.id.progressBarWait);
holder = surfaceViewFrame.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
player = new MediaPlayer();
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setScreenOnWhilePlaying(true);
player.setDisplay(holder);
}
private void playVideo() {
new Thread(new Runnable() {
public void run() {
try {
player.setDataSource(video_uri);
player.prepare();
} catch (Exception e) { // I can split the exceptions to get which error i need.
showToast("Error while playing video");
Log.i(TAG, "Error");
e.printStackTrace();
}
}
}).start();
}
private void showToast(final String string) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(VideoPlayer.this, string, Toast.LENGTH_LONG).show();
finish();
}
});
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder holder) {
playVideo();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
//prepare the video
public void onPrepared(MediaPlayer mp) {
progressBarWait.setVisibility(View.GONE);
// Adjust the size of the video
// so it fits on the screen
int videoWidth = player.getVideoWidth();
int videoHeight = player.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = surfaceViewFrame.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
surfaceViewFrame.setLayoutParams(lp);
if (!player.isPlaying()) {
player.start();
}
surfaceViewFrame.setClickable(true);
}
// callback when the video is over
public void onCompletion(MediaPlayer mp) {
mp.stop();
if (updateTimer != null) {
updateTimer.cancel();
}
finish();
}
//pause and resume
public void onClick(View v) {
if (v.getId() == R.id.surfaceViewFrame) {
if (player != null) {
if (player.isPlaying()) {
player.pause();
pause.setVisibility(View.VISIBLE);
} else {
player.start();
pause.setVisibility(View.GONE);
}
}
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
videoView1 = (VideoView) findViewById(R.id.videoview);
String SrcPath = "/mnt/sdcard/final.mp4";
videoView1.setVideoPath(SrcPath);
videoView1.setMediaController(new MediaController(this));
videoView1.requestFocus();
videoView1.start();
}
}
<VideoView
android:id="#+id/videoview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true" >
</VideoView>
try this it's working for me
The current upvoted solution works, but there may be a simpler solution to the original problem. A commenter correctly pointed out that you could resize a VideoView using the same methodology without the cost of converting everything to a SurfaceView. I tested this in one of my apps and it seems to work. Just add the calculated layout parameters to the VideoView in the OnPreparedListener callback:
mInspirationalVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
// mMediaPlayer = mp;
mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
#Override
public void onSeekComplete(MediaPlayer mp) {
if(isPlaying = true) {
stopPosition = 0;
mp.start();
mVideoProgressTask = new VideoProgress();
mVideoProgressTask.execute();
}
}
});
// so it fits on the screen
int videoWidth = mp.getVideoWidth();
int videoHeight = mp.getVideoHeight();
float videoProportion = (float) videoWidth / (float) videoHeight;
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(mDisplayMetrics);
float screenWidth = mDisplayMetrics.widthPixels;
float screenHeight = mDisplayMetrics.heightPixels;
float screenProportion = (float) screenWidth / (float) screenHeight;
android.view.ViewGroup.LayoutParams lp = mInspirationalVideoView.getLayoutParams();
if (videoProportion > screenProportion) {
lp.width = screenWidth;
lp.height = (int) ((float) screenWidth / videoProportion);
} else {
lp.width = (int) (videoProportion * (float) screenHeight);
lp.height = screenHeight;
}
mInspirationalVideoView.setLayoutParams(lp);
...
}
});
Here is my function which works for the full screen video without stretching it. It will automatically crop the sides of the video. It worked both portrait and landscape modes.
It was actually taken from the answer.
public void onPrepared(MediaPlayer mp) {
int videoWidth = mediaPlayer.getVideoWidth();
int videoHeight = mediaPlayer.getVideoHeight();
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;
int screenHeight = displayMetrics.heightPixels;
float scaleY = 1.0f;
float scaleX = (videoWidth * screenHeight / videoHeight) / screenWidth;
int pivotPointX = (int) (screenWidth / 2);
int pivotPointY = (int) (screenHeight / 2);
surfaceView.setScaleX(scaleX);
surfaceView.setScaleY(scaleY);
surfaceView.setPivotX(pivotPointX);
surfaceView.setPivotY(pivotPointY);
mediaPlayer.setLooping(true);
mediaPlayer.start();
}
Have you tried adjusting the underlying surface holder size? Try the code below it should adjust the surface holder to be the same width and height of the screen size. You should still have your activity be full screen without a title bar.
public class Video extends Activity {
private VideoView myvid;
#Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
myvid = (VideoView) findViewById(R.id.myvideoview);
myvid.setVideoURI(Uri.parse("android.resource://" + getPackageName()
+"/"+R.raw.video_1));
myvid.setMediaController(new MediaController(this));
myvid.requestFocus();
//Set the surface holder height to the screen dimensions
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
myvid.getHolder().setFixedSize(size.x, size.y);
myvid.start();
}
}
Well, I hope it helps FullscreenVideoView
It handles all boring code about surfaceView and fullscreen view and let you focus only in UI buttons.
And you can use the FullscreenVideoLayout if you don't want to build your custom buttons.
A SurfaceView gives u an optimized drawing surface
public class YourMovieActivity extends Activity implements SurfaceHolder.Callback {
private MediaPlayer media = null;
//...
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
media = new MediaPlayer();
mSurfaceView = (SurfaceView) findViewById(R.id.surface);
//...
}
}
MediaPlayer calls should be wrapped in a try{}.
#Override
public void surfaceCreated(SurfaceHolder holder) {
media.setDataSource("android.resource://" + getPackageName()
+"/"+R.raw.video_);
media.prepare();
int videoWidth = mp.getVideoWidth();
int videoHeight = mp.getVideoHeight();
int screenWidth = getWindowManager().getDefaultDisplay().getWidth();
android.view.
ViewGroup.LayoutParams layout = mSurfaceView.getLayoutParams();
layout.width = screenWidth;
layout.height = (int) (((float)videoHeight / (float)videoWidth) * (float)screenWidth);
mSurfaceView.setLayoutParams(layout);
mp.start();
}
I have solved this one by Custom VideoView:
I have added VideoView to ParentView in two ways From xml & programatically.
Add Custom class for VideoView named with FullScreenVideoView.java:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.VideoView;
public class FullScreenVideoView extends VideoView {
public FullScreenVideoView(Context context) {
super(context);
}
public FullScreenVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FullScreenVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
}
How to bind with xml:
<FrameLayout
android:id="#+id/secondMedia"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.my.package.customview.FullScreenVideoView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fullScreenVideoView"/>
</FrameLayout>
OR
How to add Programatically VideoView to ParentView:
FullScreenVideoView videoView = new FullScreenVideoView(getActivity());
parentLayout.addView(videoView, new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
Hope this will help you.