I am creating an Activity with two ImageViews.
The first ImageView occupies a part of the screen on startup and I want to show the other ImageView, whose content is a crop around the region where I touch the first Image and on TOP of it.
Class:
public class DetectEyesActivity extends Activity implements OnTouchListener {
private ImageView imgView;
private Bitmap imgBitmap;
private ImageView touchView2;
private Bitmap temp;
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.detecteyeslayout);
Intent intent = this.getIntent();
byte[] image = intent.getByteArrayExtra("Image");
imgView = (ImageView) findViewById(R.id.detectImageView1);
touchView2 = (ImageView) findViewById(R.id.detectImageView2);
imgBitmap = BitmapFactory.decodeByteArray(image, 0, image.length);
imgView.setImageBitmap(imgBitmap);
temp = Bitmap.createBitmap(imgBitmap, 200, 200, 200, 200);
//touchView2.setImageBitmap(temp);
imgView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
int y = (int)event.getY();
int x = (int)event.getX();
temp = Bitmap.createBitmap(imgBitmap, 200,200, 200, 200);
touchView2.setImageBitmap(temp);
touchView2.setVisibility(0);
touchView2.bringToFront();
touchView2.layout(x-200, y-200, x-30, y-30);
return true;
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="#+id/detectImageView1"
android:layout_width="400dp"
android:layout_height="400dp" />
<ImageView
android:id="#+id/detectImageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:visibility="gone" />
</LinearLayout>
But when I call
touchView2.setImageBitmap(temp);
Inside onTouch() the view is drawn below the initial image on the layout. But if I call it inside onCreate() it is drawn on top of the initial image?
Why does this happens, and how I can I solve this problem?
As I understand your question, you want one of your images overlayed on the other. LinearLayouts display their children in either a horizontal or vertical line. This is not a good ViewGroup to use for your case, as it does not allow multiple children to occupy the same space. I'd try either a Relative or Frame Layout.
Also, you have the second image's visibility set to gone initially, so it's not that the first image is being drawn over it, but that the second image just isn't being drawn at all until you call setVisibility in your onTouch.
Related
I have two image views, one on top of the other. Behind imageView displays user's image while the top one is cover image (just face area is fully transparent like following screenshot).
My layout is like this:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rlContainer">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ivUserImage"
android:contentDescription="#string/content_description"/>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ivCoverImage"
android:contentDescription="#string/content_description"
android:scaleType="fitXY"/>
</RelativeLayout>
I'm using OnSwipeTouchListener class in order to adjust user's shape in transparent (face) area. I have following code in onCreateView() of my fragment:
mrlContainer = (RelativeLayout) view.findViewById(R.id.rlContainer);
mUserImage = (ImageView) view.findViewById(R.id.ivUserImage);
mUserImage.setImageURI(mImgUri);
mCoverImage = (ImageView) view.findViewById(R.id.ivCoverImage);
mCoverImage.setOnTouchListener(new OnSwipeTouchListener(mContext) {
public void onSwipeTop() {
moveImageToTop();
}
public void onSwipeRight() {
moveImageToRight();
}
public void onSwipeLeft() {
moveImageToLeft();
}
public void onSwipeBottom() {
moveImageToBottom();
}
public boolean onTouch(View v, MotionEvent event) {
return getGestureDetector().onTouchEvent(event);
}
});
And my movement methods are these:
private void moveImageToTop() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.topMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
private void moveImageToBottom() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.bottomMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
private void moveImageToRight() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.rightMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
private void moveImageToLeft() {
LayoutParams layoutParams = (LayoutParams) mUserImage.getLayoutParams();
layoutParams.leftMargin -= 20;
mUserImage.setLayoutParams(layoutParams);
}
Now, moveImageToTop() and moveImageToBottom() are working fine when I touch screen and move my finger top or bottom. However, image scales up when I move left or right.
What you think? Where is my mistake? Any suggestion would be appreciated. Thanks
As I know, default image scaleType is FIT_CENTER. You didn't change only position since you set MATCH_PARENT in both axis. Also you change View boundaries. By changing vertical boundaries you didn't change image size inside ImageView if your image is fit in horizontal axis.
If I were you, I will use Animation framework or change position during onLayout change and ask for relayout after every swipe.
I changed xml code of behind image to following code and left/right movement fixed:
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/ivUserImage"
android:contentDescription="#string/content_description"
android:scaleType="center"/>
Anyway, I decided to use PhotoView library by chrisbanes which is very easy to use.
I inflate a layout containing an ImageView and a RelativeLayout. The layout has its width set to match_parent and its height set to wrap_content. The height is determined by the ImageView, but the image set to the ImageView is loaded dynamically from the internet.
Since I know the image ratio, I'd like to set the size of the ImageView before it's displayed to avoid a jump in the UI due to the change in the layout height when the image is set.
To set the size I need the layout width, to compute the ImageView height.
I tried
int width = header.getMeasuredWidth();
but since the layout is not drawn yet it returns 0
I also tried to use measure before, as suggested here
header.measure(0, 0);
int width = header.getMeasuredWidth();
but measure returns a NullPointerException
How can I do that?
list_header.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/pic"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<RelativeLayout
android:id="#+id/header_text_container"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="#789987">
</RelativeLayout>
</RelativeLayout>
MyListFragment.java
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mListView = (ListView) getView().findViewById(R.id.listview);
View header = getActivity().getLayoutInflater().inflate(R.layout.list_header, null);
int width = header.getMeasuredWidth(); // 0 because not drawn yet
ImageView pic = (ImageView) header.findViewById(R.id.pic);
pic.setLayoutParams(new LayoutParams(width, (int) (width/imgRatio)));
pic.invalidate();
header.invalidate();
/* ... */
}
You could try with a ViewTreeObserver.
Your Fragment/Activity should implement OnGlobalLayoutListener, in OnActivityCreate declare handler
ViewGroup container = (ViewGroup) findViewById(R.id.header_text_container)
ViewTreeObserver vto = container.getViewTreeObserver();
vto.addOnGlobalLayoutListener(this);
and put your width logic in listener when size are available
#Override
public void onGlobalLayout() {
// Remember to remove handler
container.getViewTreeObserver().removeGlobalOnLayoutListener(this);
View header = getActivity().getLayoutInflater().inflate(R.layout.list_header, null);
int width = header.getMeasuredWidth(); // 0 because not drawn yet
...
}
you can get the size in Activity's onWindowFocusChanged(boolean hasFocus) method.
You can get the width and height of a view in onGlobalLayout, wich is a method to Callback method wich is invoked when the global layout state or the visibility of views within the view tree changes (thus as soon as the view is drawn and the size is known).
ViewTreeObserver vto = header.getViewTreeObserver();
if(vto!=null){
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
header.getWidth();
header.getHeight();
}
});
}
So, I have a Layout that contains a Button and an ImageView. When you press the button the ImageView should slide out from the button like I just pulled down a rolldown curtain (bushing other views below it down). Basically what the image below show. When you press the button again the ImageView should, unlike the gif, smoothly animates up again.
.
Using this SO question I've managed to animate the height from 0 to full size but in the wrong direction. I set the scaleType to "Matrix" and the default behaviour when setting the height is to show the part from the top down to [height].
For the animation I'll need the opposite. So if I would set the height to 50dp it would show the bottom 50dp. Then I can move the ImageView down at the same time it's being revealed, thus giving the rolldown curtain effect.
I've looked throught all the different layout and view options and found nothing that seems to do this. So I'm guessing I need to specify the transformation matrix. I looked through the android.graphics.Matrix class but it's a little but too complicated for me. I simply have no idea how to use it.
If there is another, easier, way to do this then that would be fantastic but if not then I really need help with the matrix.
I'm also including the code here:
The Rolldown View XML
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/sliding_accordion"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="#drawable/acc_image"
android:contentDescription="#string/accord"
android:scaleType="matrix"
android:layout_below="#+id/acc_button"
android:layout_marginTop="-10dp"
android:layout_centerHorizontal="true"/>
<Button
android:id="#+id/acc_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</RelativeLayout>
The implementation in code.
(Note, the MyCustomAnimation class is a copy-paste version of the class found here)
//Called from all constructors
private void create()
{
final Context context = getContext();
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.widget_accordion, this, false);
final Button theButton = (Button) layout.findViewById(R.id.topic_button);
final ImageView accordionView = (ImageView) layout.findViewById(R.id.sliding_accordion);
accordionView.setVisibility(INVISIBLE);
theButton.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v)
{
if (accordionView.getVisibility() == View.VISIBLE)
{
MyCustomAnimation a = new MyCustomAnimation(accordionView, 1000, MyCustomAnimation.COLLAPSE);
height = a.getHeight();
accordionView.startAnimation(a);
}
else
{
MyCustomAnimation a = new MyCustomAnimation(accordionView, 1000, MyCustomAnimation.EXPAND);
a.setHeight(height);
accordionView.startAnimation(a);
}
}
});
this.addView(layout);
}
This took a long time perfect. But I managed to do it after a lot of experimenting.
I animate the margins of the drawer but because of the unexpected behavior of negative margins the button that opens the drawer can not be positioned on top.
When the drawer is closed the XML looks like so:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/accordion"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.animationtest.drawer.Drawer
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/topic_drawer"
android:layout_centerHorizontal="true"
android:layout_marginTop="0dp"
android:visibility="invisible"/>
<com.animationtest.drawer.Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/topic_btn"
android:layout_marginTop="58dp"/>
</RelativeLayout>
Then when the button is pressed the top_margin of the drawer is increased until it has come to whatever position is needed (in this case drawerHeight - someOffset).
I used android.view.animation.Animation to animate the widget my applyTransformation function looks something like this (Note that mLayoutParams are the drawer params):
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int valueDifference = Math.abs(startValue - endValue);
float valueChange = interpolatedTime * valueDifference;
if(currentState.equals(State.COLLAPSED)) {
// is closed and I want to open it
mLayoutParams.topMargin = Math.round(interpolatedTime * valueDifference);
}
else {
// is opened and I want to close it
mLayoutParams.topMargin = valueDifference - Math.round(interpolatedTime * valueDifference);
}
drawerView.requestLayout(); //this is my drawer
}
Finally, to hide the top of the drawer as it moves, I overrode my DrawerView's dispatchDraw method to looks like so:
#Override
protected void dispatchDraw(Canvas canvas) {
float height = getHeight();
float top = height - ((LayoutParams) getLayoutParams()).topMargin;
Path path = new Path();
RectF rectF = new RectF(0.0f, top, getWidth(), height);
path.addRoundRect(rectF, 0.0f, 0.0f, Path.Direction.CW);
canvas.clipPath(path);
super.dispatchDraw(canvas);
}
One final note:
Because of the Button's position one would need to set the widgets margin as a negative number for it to align correctly in a list or layout. In this case it would have to be -58dp.
There is scroll view between header(at the top of screen) and Tabs(Bottom of the screen). I want to know that whether the ImageView which is inside the ScrollView is fully visible or not on phone screen window.
I would suggest to do the following way (the approach is similar to one in this question).
E.g. You have the following xml (I'm not sure what are header and tabs so they are missed):
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:id="#+id/scroller">
<ImageView
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="center"
android:id="#+id/image"
android:src="#drawable/image001"
android:scaleType="fitXY" />
</ScrollView>
Then activity might look like the following:
public class MyActivity extends Activity {
private static final String TAG = "MyActivity";
private ScrollView mScroll = null;
private ImageView mImage = null;
private ViewTreeObserver.OnGlobalLayoutListener mLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
final Rect imageRect = new Rect(0, 0, mImage.getWidth(), mImage.getHeight());
final Rect imageVisibleRect = new Rect(imageRect);
mScroll.getChildVisibleRect(mImage, imageVisibleRect, null);
if (imageVisibleRect.height() < imageRect.height() ||
imageVisibleRect.width() < imageRect.width()) {
Log.w(TAG, "image is not fully visible");
} else {
Log.w(TAG, "image is fully visible");
}
mScroll.getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener);
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Show the layout with the test view
setContentView(R.layout.main);
mScroll = (ScrollView) findViewById(R.id.scroller);
mImage = (ImageView) findViewById(R.id.image);
mScroll.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
}
}
In case of small image it will log: image is fully visible.
However, You should be aware about the following inconsistency (as per my understanding): if You have big image, but doing scaling to it (e.g. you set android:layout_width="wrap_content") when it will look scaled, but actual ImageView height will be as full height of the image (and ScrollView will be even scrolling), so adjustViewBounds might be needed. The reason for that behavious is that FrameLayout doesn't care about layout_width and layout_height of childs.
i have two image views which translates on click.
the animation works properly for one view but for second image view , my animation is not according to coordinates provided.
when i click top image view (img1) it animates properly toward bottom image view (img2) . But when i click the bottom image view, it animates from somewhere down and move towards image view 2 initial position only. though the expected behaviour is, it should animate from its position to top image view (img1) initial position.
My xml is
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="#drawable/letter_f"
android:layout_alignParentTop="true"
android:id="#+id/imgview1"
android:background="#drawable/chart"/>
<ImageView android:layout_height="100dp"
android:layout_width="100dp"
android:id="#+id/imgview2"
android:src="#drawable/letter_g"
android:background="#drawable/chart"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
and my java class file is
public class AnimationDemo extends Activity implements OnClickListener
{
private ImageView img1;
private ImageView img2;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
img1 = (ImageView)findViewById(R.id.imgview1);
img2 = (ImageView)findViewById(R.id.imgview2);
img1.setOnClickListener(this);
img2.setOnClickListener(this);
}
#Override
public void onClick(View arg0)
{
int x1,y1; // Coordinates of first image view
int x2,y2; //Coordinates of second image view
ImageView img = (ImageView)arg0;
x1 = img1.getLeft();
y1 = img1.getTop();
x2 = img2.getLeft();
y2 = img2.getTop();
TranslateAnimation slide;
if(arg0 == img1)
{
//translate from img view 1 to img view 2
slide = new TranslateAnimation(Animation.ABSOLUTE,x1,Animation.ABSOLUTE, x2,Animation.ABSOLUTE, y1,Animation.ABSOLUTE,y2 );
}
else
{
// translate from img view 2 to img view 1
slide = new TranslateAnimation(Animation.ABSOLUTE,x2,Animation.ABSOLUTE, x1,Animation.ABSOLUTE, y2,Animation.ABSOLUTE,y1);
}
slide.setDuration(1000);
slide.setFillAfter(true);
img.startAnimation(slide);
}
}
Your troubles are due to your locations. I believe when animations are moved with absolute pixels it is relative to itself. So on your second animation you were in essence moving it from x2=220 to x1=0, and y2=419 to y1=0. So it was moving from (currentX+220, currentY+419) to (currentX +0, currentY +0) which = itself
To solve this instance simply negate and switch the values of the second slide declaration like so:
TranslateAnimation slide;
if(arg0 == img1)
{
//translate from img view 1 to img view 2
slide = new TranslateAnimation(Animation.ABSOLUTE,x1,Animation.ABSOLUTE, x2,Animation.ABSOLUTE, y1,Animation.ABSOLUTE,y2 );
}
else
{
// translate from img view 2 to img view 1
// slide = new TranslateAnimation(Animation.ABSOLUTE,x2,Animation.ABSOLUTE, x1,Animation.ABSOLUTE,y2,Animation.ABSOLUTE,y1);
slide = new TranslateAnimation(Animation.ABSOLUTE,0,Animation.ABSOLUTE, (-x2),Animation.ABSOLUTE,0,Animation.ABSOLUTE, (-y2));
}
This only happens because your top left sprite is at 0,0 though. You have to seriously rethink how you're moving your sprites around. Just remember, the TranslateAnimation moves them relative to their current positions, basically setting the sprites original location to (0,0).
Could be wrong, but hope it helps. It worked for me...
Sorry it took so long to get back to you, I lost your post and couldn't find it again for some reason. Glad you had commented earlier!