I've a problem from last 2 days and unable to tackle it as I'm newbie. Actually I'm working on an Android App that needs pinch-zoom and 2-finger rotation on Android ImageView. I got the multiple tutorials and solutions that work fine for Pinch Zoom and but does not work for 2 finger rotation. I'm sharing the simplest tutorial that's easy to understand and I want to extend it for 2 finger rotation. Here is the code snippet:
public class MainActivity extends Activity {
private ImageView mImageView;
private Matrix mMatrix = new Matrix();
private float mScale = 1f;
private ScaleGestureDetector mScaleGestureDetector;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mImageView = (ImageView) findViewById(R.id.imageView);
mScaleGestureDetector = new ScaleGestureDetector(this, new ScaleListener());
}
public boolean onTouchEvent(MotionEvent ev) {
mScaleGestureDetector.onTouchEvent(ev);
return true;
}
private class ScaleListener extends ScaleGestureDetector.
SimpleOnScaleGestureListener {
#Override
public boolean onScale(ScaleGestureDetector detector) {
mScale *= detector.getScaleFactor();
mScale = Math.max(0.1f, Math.min(mScale, 5.0f));
mMatrix.setScale(mScale, mScale);
mImageView.setImageMatrix(mMatrix);
return true;
}
}
}
Also I want to use them for GPUImage, I mean despite of Android ImageView I want to use GPUImage. How to transform the GPUImage to ImageView? This is the 2nd thing. First I want to implement the 2 finger rotation (or MultiTouch in some sense). Thanks
Here is the solution that worked good for me. https://stackoverflow.com/a/18276033 Only one line I should add here and that should be
add imageView.setRotation(imageView.getRotation() + (-angle)); in OnRotation(RotationGestureDetector rotationDetector) method inside the activity to set the new rotation value to the ImageView
This is for basic help. Remaining of the implementation is just fine
This is the library I created, which creates a imageview class can drag, rotate and zoom
Requirement: (Add on build.gradle)
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Add Dependency
dependencies {
implementation 'com.github.lau1944:Zoom-Drag-Rotate-ImageView:1.0.0'
}
first , add image on xml:
<com.easystudio.rotateimageview.RotateZoomImageView
android:id="#+id/rotate"
android:layout_width="150dp"
android:layout_height="150dp"
android:src="#drawable/money"/>
or add programmatically:
RotateZoomImageView iv;
RelativeLayout playground = findViewById(R.id.playground);
iv = new RotateZoomImageView(getApplicationContext());
iv.setImageDrawable(getDrawable(R.drawable.money));
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(250, 250);
lp.addRule(RelativeLayout.BELOW);
iv.setLayoutParams(lp);
playground.addView(iv);
Step 2 : set up ontouchmethod
iv.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
return iv.onTouch(v,event);
}
});
And that is it .
Related
I am using this Library in order to create a transform effect on a pager. All the classes working good except for the Cube Out and Cube In transform. They appear white while scrolling.
I have also created a custom animation but it still not animate the pager.
What could be the problem here? and why only setRotationY is not working properly?
public class CubePageTrasformer extends BaseTransformer {
#Override
protected void onTransform(View view, float position) {
final float height = view.getHeight();
final float width = view.getWidth();
view.setPivotX(position < 0f ? width : 0f);
view.setPivotY(height * 0.5f);
float rotation = (90f * position);
view.setRotationY(rotation);
}
#Override
public boolean isPagingEnabled() {
return true;
}
}
I had the exact same issue as you and I found that the following change fixed the issue on all devices:
viewPager.clipChildren = false
I'm stuck on this problem in Android Drag and Drop. I've already read the documentation and more than one question/answer here on stackoverflow .
The problem is that:
i've 3 ImageView that can i move inside another 3 ImageView, but when i start to drag one of the 3 ImageView i can drop it inside in just one ImageView area.
Here the code! . Basically i'll see active only the dropViewArancio area even if i drag the other ImageView.
What i want it's to have all the 3 area active where i can drop one of the 3 ImageView.
Thanks for the support!
An ImageView can't contain another View inside, only classes derived from ViewGroup can. Then you can move an ImageView over or behind another (depending on Z order) but not inside.
Here a working example of how to move all the views contained in a RelativeLayout using onTouch. I think that onDrag event applies better to drag and drop data items, not to move views. Hope it will help
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
private RelativeLayout mRelLay;
private float mInitialX, mInitialY;
private int mInitialLeft, mInitialTop;
private View mMovingView = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRelLay = (RelativeLayout) findViewById(R.id.relativeLayout);
for (int i = 0; i < mRelLay.getChildCount(); i++)
mRelLay.getChildAt(i).setOnTouchListener(this);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
RelativeLayout.LayoutParams mLayoutParams;
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
mMovingView = view;
mLayoutParams = (RelativeLayout.LayoutParams) mMovingView.getLayoutParams();
mInitialX = motionEvent.getRawX();
mInitialY = motionEvent.getRawY();
mInitialLeft = mLayoutParams.leftMargin;
mInitialTop = mLayoutParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
if (mMovingView != null) {
mLayoutParams = (RelativeLayout.LayoutParams) mMovingView.getLayoutParams();
mLayoutParams.leftMargin = (int) (mInitialLeft + motionEvent.getRawX() - mInitialX);
mLayoutParams.topMargin = (int) (mInitialTop + motionEvent.getRawY() - mInitialY);
mMovingView.setLayoutParams(mLayoutParams);
}
break;
case MotionEvent.ACTION_UP:
mMovingView = null;
break;
}
return true;
}
}
So, i've solved my problem following this tutorial. Anyway my desire solution it's something similar this, the perfect way it's a mixing of tutorial and a previous link. Thanks all for help.
I wrote the following code and it works well. But I have other purpose. I want to click only on a view to doing the operations.First, Please see the following image:
MY CODE IS AS FOLLOWS:
public class MainActivity extends Activity {
RelativeLayout relativeLayout;
#Override
protected void onCreate(Bundle bundle)
{ super.onCreate(bundle);
relativeLayout = new RelativeLayout(getApplicationContext());
setContentView(relativeLayout);
A a = new A(this);
relativeLayout.addView(a);
a.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
B b = new B(getApplicationContext());
relativeLayout.addView(b);
}
});
}
}
class A extends View {
Paint paint;
A(Context context) {
super(context);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas) {
paint.setAntiAlias(true);
paint.setColor(Color.RED);
canvas.drawRect(20,60,100,150,paint);
}
}
class B extends View {
Paint paint;
B(Context context){
super(context);
paint = new Paint();
}
#Override
protected void onDraw(Canvas canvas){
paint.setAntiAlias(true);
paint.setColor(Color.GREEN);
canvas.drawRect(100,150,200,250,paint);
}
}
when I run the above code I can see the green rectangle after press on the red rectangle. But the problem is that when I press another places on the screen I can do this operations also. I want that only I can see the green rectangle to press on the red rectangle and not in the another places on the screen to doing this operations.
Use onTouch event
a.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getX(0)>=20 && event.getY(0)>=60 && event.getX(0)<=160 && event.getY(0)<=150) {
B b = new B(getApplicationContext());
relativeLayout.addView(b);
}
return true;
}
});
You are defining the red square's parameters but not the parameters of the canvas in which you are drawing. You are creating the view (A) without defining the width and height of it, so it is set to match_parent by default, which means it will take the whole size of your RelativeLayout (the whole screen). So, when you click "outside" the red square you are actually clicking the view (A).
Try to define an specific height and width for the view in which you are drawing, like this.
A a = new A(this);
a.setLayoutParams(new RelativeLayout.LayoutParams(300,300));
Remember that LayoutParams takes pixels as parameters, so you should really convert the dps to px as specified here
Also, setting some background colors to your views (relativeLayout, A) will help you visualize what you are doing.
# nukeforum, your guess helped me very much. I thank all of you. My problem was exactly from the canvas and its size. I added the following operation in my code and solved my problem.
relativeLayout.addView(a,70,70);
For A class, I changed as follows:
canvas.drawRect(10,20,30,40,paint);
Im trying to make an Imageview (a ball) move around the layout and bounce a number of times before stoping when a buttom is pressed. The probles is that although the logcat says its happening, i dont see it moving.
Here it is
public class BallPhisics {
int x =400;
int y = 0;
boolean bounceX = false;
boolean bounceY= false;
int counter =0;
ImageView object;
public BallPhisics(ImageView i){
object=i;
}
public void applyMovement() {
while (true) {
object.setLeft((int) object.getX()+x); //i know i shouldnt use pixels
Log.d("EVENT", "X moved"); Log.d("Ended",Integer.toString(object.getLeft()));
object.setBottom((int)(object.getY() + y));
Log.d("EVENT", "Y moved");
try {
Thread.sleep(1000);
Log.d("EVENT", "Time 1 used");
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
if (object.getX()<=50||(object.getRight()<=50)){
bounceX =true;
break;
}
if (object.getY()<=50||object.getTop()<=50){
bounceY=true;
break;
}
}
this.bouncing();
}
public void bouncing(){
Log.d("EVENT", "Bouncing!!");
if (bounceX&&bounceY){
x=-x;
y=-y;
}
else if (bounceX){
x=-x;
y=(int)(Math.random()*100- 50 +y);
}
else if (bounceY) {
x = (int) (Math.random() * 100 - 50 + x);
y = -y;
}
counter++;
if(counter==5){return;}
this.applyMovement();
}
And on mainActivity the onclick event.
public void StartBall (View view){
ImageView imageview=(ImageView) findViewById(R.id.imageView);
BallPhisics phisics = new BallPhisics(imageview);
Log.d("EVENT", Integer.toString(imageview.getLeft() )+" before");
phisics.applyMovement();
Log.d("EVENT",Integer.toString(imageview.getLeft())+" after" );
}
Sorry if it is a lot of reading. By the way does anyone knows the proper way of moving a view?
Thanks in advance
First of all to move a View it's probably not a good idea to use setLeft (int left) or setBottom (int bottom) because this method is meant to be called by the layout system and should not generally be called otherwise, according to the documentation.
To move a View dynamically you should take a look at LayoutParams or setX (float x) and setY (float Y), if you can limit your support to Honeycomb (API Level 11).
Regardless which one you use, you may find it difficult to achieve a smooth movement. Therefore I recommend you to use the view animation system to perform tweened animation of your ImageView.
Below you will find an example of a chain animation that moves an ImageView starting from left to right with an arbitrary y-coordinate. After each translation from one x-border to the next, the onAnimationEnd will be called and start an animation in the other direction.
public class MainActivity extends Activity {
//the ImageView you want to animate
private ImageView imageview;
private Animation mAnimation;
//The coordinates the view moved to in the last animation
private float lastX=0;
private float lastY=0;
private float secondlastY;
//Listener that implements a translate animation chain
AnimationListener animationListener=new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
float newY=(float)(Math.random()*0.75);
//this prevents that we move back to the position we came from
// to get a more natural bounce animation
while(newY<=secondlastY+0.15 && newY>=secondlastY-0.15){
newY=(float)(Math.random()*0.75);
}
if(lastX==0.75f){
//test if we are on the right border of the parent
mAnimation=newAnimation(lastX,lastY,0f,newY);
mAnimation.setAnimationListener(animationListener);
lastX=0f;
}else if(lastX==0.0f){
//test if we are on the left border of the parent
mAnimation=newAnimation(lastX,lastY,0.75f,newY);
mAnimation.setAnimationListener(animationListener);
lastX=0.75f;
}
secondlastY=lastY;
lastY=newY;
imageview.startAnimation(mAnimation);
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageview=(ImageView) findViewById(R.id.imageView);
//the coordinates the first animation should move to
lastY=(float)(Math.random()*0.75);
lastX=0.75f;
mAnimation=newAnimation(0f,0f,lastX,lastY);
mAnimation.setAnimationListener(animationListener);
imageview.startAnimation(mAnimation);
}
//Method that returns a new animation with given start and end coordinates
private Animation newAnimation(float startX, float startY, float endX, float endY){
Animation mAnimation = new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_PARENT, startX,
TranslateAnimation.RELATIVE_TO_PARENT, endX,
TranslateAnimation.RELATIVE_TO_PARENT, startY,
TranslateAnimation.RELATIVE_TO_PARENT, endY );
mAnimation.setDuration(2500);
mAnimation.setRepeatCount(0);
mAnimation.setRepeatMode(Animation.REVERSE);
mAnimation.setFillAfter(true);
return mAnimation;
}
}
Note:
The translation animation is relative to the parents width and height. If you move the View all the way to x=1.0 or y=1.0 you will move parts of the view out of the parent layout. Because it's sufficient for this example I chose to set 0.75 to the max position in either direction. But you should probably set this dynamically in regards to the width and height of your ImageView and ParentLayout.
I have to be missing something obvious, since everyone on the planet seems to be able to get the whole pinch-zoom thing to work. The main difference is most folks seem to be zooming on images, whereas I've a GridLayout (android-support-v7-gridlayout) with a bunch of text views. The goal seems simple enough: Allow the user to zoom in so that they can view a portion of the full grid at a larger size.
The grid draws fine, and horizontal & vertical scrolling work fine. And then, when I do a two-finger gesture with fingers moving apart (zoom), nothing happens, despite getting the log message that onScale has been called. When I move the two fingers in (pinch), all the views disappear (though my scroll bars are left).
I've looked at Matrix transformations but haven't seen that those work on anything but an image view.
The basic layout xml:
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<HorizontalScrollView
android:id="#+id/chooser_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</HorizontalScrollView>
</ScrollView>
Then in the activity
private ZoomGridLayout playerGrid;
and in onCreate:
ViewGroup gridParent = (ViewGroup) findViewById(R.id.chooser_layout);
playerGrid = new ZoomGridLayout(getBaseContext());
playerGrid.setRowCount(8);
playerGrid.setColumnCount(8);
LayoutParams layout =
new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
playerGrid.setDetector();
gridParent.addView(playerGrid, layout);
I then proceed to add ~150 small text views to the grid.
Here's the first take at ZoomGridLayout:
public class ZoomGridLayout extends GridLayout {
private final static String TAG = "ZGL";
private ScaleGestureDetector scaleDetector;
private Context context;
public void setDetector() {
scaleDetector = new ScaleGestureDetector(context, new ScaleGesture());
}
public ZoomGridLayout(Context c) {
super(c);
context = c;
}
#Override
public boolean onTouchEvent (MotionEvent event) {
scaleDetector.onTouchEvent(event);
return true;
}
private class ScaleGesture
extends ScaleGestureDetector.SimpleOnScaleGestureListener
{
#Override
public boolean onScale(ScaleGestureDetector detector) {
Log.v(TAG, detector.toString());
ScaleAnimation scale =
new ScaleAnimation(detector.getPreviousSpan(),
detector.getCurrentSpan(),
detector.getPreviousSpan(),
detector.getCurrentSpan());
scale.setFillAfter(true);
startAnimation(scale);
return true;
}
}
}
I've been beating my head against this for a couple days now. I'm new to Android programming, so not very familiar with the libraries, but I'm an experienced developer. Any pointers would be wonderful. TIA.
I gave up on animations (though eventually I'd like to try to make that work). Here's the new onScale method:
#Override
public boolean onScale(ScaleGestureDetector detector) {
Log.v(TAG, detector.toString());
mScaleFactor *= detector.getScaleFactor();
// Don't let the object get too small or too large.
mScaleFactor = Math.max(MIN_SCALE, Math.min(mScaleFactor, MAX_SCALE));
invalidate();
return true;
}
this is then complemented by overriding the draw method:
#Override
public void dispatchDraw(Canvas canvas) {
String disp = String.valueOf(mScaleFactor);
Log.v(TAG, "dispatch draw " + disp);
canvas.save();
canvas.scale(mScaleFactor, mScaleFactor);
super.dispatchDraw(canvas);
canvas.restore();
}
i also learned that since the parent is a ViewGroup instead of a View, that one needs to override the dispatch… methods instead of the on… methods.
there are so many different variants of this pattern out there. i hope this particular wrinkle helps someone else.