I want to create a custom menu for my Android application like iPhone's https://github.com/XavierDK/XDKAirMenu . My application shows menu on left side of the screen and its content on right side of the screen.
This the custom layout for right side of the screen(content view)
public boolean onTouchEvent(MotionEvent event) {
gestureDetector.onTouchEvent(event);
if (isTranformed) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this .getLayoutParams();
if (layoutParams.leftMargin == 0 && layoutParams.topMargin == 0) {
//requestLayout();
isTranformed = false;
isScrolling = false;
break;
}
isScrolling = true;
int xDiff = layoutParams.leftMargin - (X - _xDelta);
layoutParams.leftMargin = X - _xDelta;
int scaleFactor = layoutParams.leftMargin > 0 ? layoutParams.leftMargin : 1;
layoutParams.topMargin = layoutParams.topMargin - ((layoutParams.topMargin / scaleFactor) * xDiff);
if (layoutParams.leftMargin < 0) {
layoutParams.leftMargin = 0;
}
if (layoutParams.topMargin < 0) {
layoutParams.topMargin = 0;
}
layoutParams.width = (displayMetrics.widthPixels - layoutParams.leftMargin);
layoutParams.height = (displayMetrics.heightPixels - (layoutParams.topMargin * 2));
this.setLayoutParams(layoutParams);
//invalidate();
//setLeft(layoutParams.leftMargin);
//setTop(layoutParams.topMargin);
/* this.setX(layoutParams.leftMargin);
this.setY(layoutParams.topMargin);*/
this.requestLayout();
break;
case MotionEvent.ACTION_UP:
if (isScrolling) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) CustomSlidingLayout.this
.getLayoutParams();
if (params.leftMargin < displayMetrics.widthPixels / 2) {
if (!isAnimating) {
isAnimating = true;
ResizeMoveAnimation anim = new ResizeMoveAnimation(
this, 0, 0, displayMetrics.widthPixels,
displayMetrics.heightPixels);
anim.setAnimationListener(animationListener);
startAnimation(anim);
}
} else {
if (!isAnimating) {
isAnimating = true;
Rect rect = new Rect();
getLocalVisibleRect(rect);
ResizeMoveAnimation anim = new ResizeMoveAnimation(
this, (int) (displayMetrics.widthPixels * 0.8),
displayMetrics.heightPixels / 4,
displayMetrics.widthPixels * 2,
(int) (displayMetrics.heightPixels * 0.75));
// anim.setAnimationListener(animationListener);
startAnimation(anim);
isAnimating = false;
}
}
isScrolling = false;
}
break;
case MotionEvent.ACTION_DOWN:
FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) this
.getLayoutParams();
_xDelta = X - lParams.leftMargin;
break;
}
return true;
}
return false;
}
}
View on the right side(content view) resize to a small size when click on menu button.and it resize to its original size when touch on the resized view.Also, i want to scale and move the view from right-to left on touch. The above code snippet have some view position issues. It does not update the view layout/position correctly.How can i fix it?
Use this code to achieve the scaling and transition animation
float scalefactor = 0.5;
float translateX = 500; // Translate amount
view.animate().scaleX(scalefactor).translationXBy(translateX).start();
for reverse animation
view.animate().scaleX(1).translationXBy(-translateX).start();
Related
I have a view-group (ZoomableViewGroup is my custom class extending ViewGroup) in my layout as parent, which inside contains a relative layout. The width and height of ViewGroup is by default 2286 height and 1600 width which is larger than device size. How to set the ViewGroup size to screen size ? My final expected result is, I am trying to zoom and pan the relative out, it moves out of screen due to the huge size of ViewGroup.
<com.example.pdoc.zoomablepdf.ZoomableViewGroup
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/zoomLayout"
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#drawable/samplebg"
android:id="#+id/RelLayout">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="#+id/LinLayout">
</LinearLayout>
</RelativeLayout>
</com.example.pdoc.zoomablepdf.ZoomableViewGroup>
Java code
ZoomableViewGroup mZoomableViewGroup;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mainnew);
mZoomableViewGroup = (ZoomableViewGroup) findViewById(R.id.zoomLayout);
LinearLayout ll = (LinearLayout)findViewById(R.id.LinLayout);
//add edittext dynamically
EditText myText = new EditText(MainnewActivity.this);
myText.setText("Edit Me");
LinearLayout.LayoutParams lp = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
lp.gravity= Gravity.CENTER_HORIZONTAL;
ll.addView(myText, lp);
//add checkbox dynamically
CheckBox myChk = new CheckBox(MainnewActivity.this);
myChk.setText("Check me");
LinearLayout.LayoutParams chklp = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
chklp.gravity= Gravity.CENTER_HORIZONTAL;
ll.addView(myChk, chklp);
//add imageview dynamically
ImageView myImg = new ImageView(MainnewActivity.this);
myImg.setImageResource(R.drawable.apple);
LinearLayout.LayoutParams imgLP = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
imgLP.gravity= Gravity.CENTER_HORIZONTAL;
ll.addView(myImg, imgLP);
//add button dynamically
Button mybtn1 = new Button(MainnewActivity.this);
mybtn1.setText("Click me");
LinearLayout.LayoutParams btnLP = new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
btnLP.gravity= Gravity.CENTER_HORIZONTAL;
ll.addView(mybtn1, btnLP);
mybtn1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainnewActivity.this, "6--"+ mZoomableViewGroup.getHeight() + "_" + mZoomableViewGroup.getWidth(),Toast.LENGTH_SHORT).show();
}
});
}
ZoomableViewGroup class code
public class ZoomableViewGroup extends ViewGroup {
// States.
private static final byte NONE = 0;
private static final byte DRAG = 1;
private static final byte ZOOM = 2;
private static final byte DTAP = 3;
private byte mode = NONE;
// Matrices used to move and zoom image.
private Matrix matrix = new Matrix();
private Matrix matrixInverse = new Matrix();
private Matrix savedMatrix = new Matrix();
// Parameters for zooming.
private PointF start = new PointF();
private PointF mid = new PointF();
private float oldDist = 1f;
private float[] lastEvent = null;
private long lastDownTime = 0l;
private float[] mDispatchTouchEventWorkingArray = new float[2];
private float[] mOnTouchEventWorkingArray = new float[2];
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
mDispatchTouchEventWorkingArray[0] = ev.getX();
mDispatchTouchEventWorkingArray[1] = ev.getY();
mDispatchTouchEventWorkingArray = screenPointsToScaledPoints(mDispatchTouchEventWorkingArray);
ev.setLocation(mDispatchTouchEventWorkingArray[0], mDispatchTouchEventWorkingArray[1]);
return super.dispatchTouchEvent(ev);
}
public ZoomableViewGroup(Context context) {
super(context);
Toast.makeText(context, "c1-" + this.getHeight() + "_" + this.getWidth(), Toast.LENGTH_SHORT).show ();
init(context);
}
public ZoomableViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
Toast.makeText(context, "c2-" + this.getHeight() + "_" + this.getWidth(), Toast.LENGTH_SHORT).show ();
init(context);
}
public ZoomableViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
Toast.makeText(context, "c3-" + this.getHeight() + "_" + this.getWidth(), Toast.LENGTH_SHORT).show ();
init(context);
}
private void init(Context context) {
}
//Determine the space between the first two fingers
private float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
//Calculate the mid point of the first two fingers
private void midPoint(PointF point, MotionEvent event) {
float x = event.getX(0) + event.getX(1);
float y = event.getY(0) + event.getY(1);
point.set(x / 2, y / 2);
}
private float[] scaledPointsToScreenPoints(float[] a) {
matrix.mapPoints(a);
return a;
}
private float[] screenPointsToScaledPoints(float[] a) {
matrixInverse.mapPoints(a);
return a;
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//super.onLayout(changed, left, top, right, bottom);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
child.layout(child.getLeft(), child.getTop(), child.getLeft()+child.getMeasuredWidth(), child.getTop()+child.getMeasuredHeight());
}
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//measure(widthMeasureSpec, heightMeasureSpec);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != GONE) {
measureChild(child, widthMeasureSpec, heightMeasureSpec);
}
}
//measure(widthMeasureSpec, heightMeasureSpec);
}
#Override
protected void dispatchDraw(Canvas canvas) {
float[] values = new float[9];
matrix.getValues(values);
canvas.save();
canvas.translate(values[Matrix.MTRANS_X], values[Matrix.MTRANS_Y]);
canvas.scale(values[Matrix.MSCALE_X], values[Matrix.MSCALE_Y]);
super.dispatchDraw(canvas);
canvas.restore();
}
#Override
public boolean onTouchEvent(MotionEvent event) {
// handle touch events here
mOnTouchEventWorkingArray[0] = event.getX();
mOnTouchEventWorkingArray[1] = event.getY();
mOnTouchEventWorkingArray = scaledPointsToScreenPoints(mOnTouchEventWorkingArray);
event.setLocation(mOnTouchEventWorkingArray[0], mOnTouchEventWorkingArray[1]);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
savedMatrix.set(matrix);
mode = DRAG;
lastEvent = null;
long downTime = event.getDownTime();
if (downTime - lastDownTime < 300l) {
float density = getResources().getDisplayMetrics().density;
if (Math.max(Math.abs(start.x - event.getX()), Math.abs(start.y - event.getY())) < 20.f * density) {
savedMatrix.set(matrix);
mid.set(event.getX(), event.getY());
mode = ZOOM;
lastEvent = new float[4];
lastEvent[0] = lastEvent[1] = event.getX();
lastEvent[2] = lastEvent[3] = event.getY();
}
lastDownTime = 0l;
} else {
lastDownTime = downTime;
}
start.set(event.getX(), event.getY());
break;
case MotionEvent.ACTION_POINTER_DOWN:
oldDist = spacing(event);
if (oldDist > 10f) {
savedMatrix.set(matrix);
midPoint(mid, event);
mode = ZOOM;
}
lastEvent = new float[4];
lastEvent[0] = event.getX(0);
lastEvent[1] = event.getX(1);
lastEvent[2] = event.getY(0);
lastEvent[3] = event.getY(1);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
mode = NONE;
lastEvent = null;
break;
case MotionEvent.ACTION_MOVE:
final float density = getResources().getDisplayMetrics().density;
if (mode == DRAG) {
matrix.set(savedMatrix);
float dx = event.getX() - start.x;
float dy = event.getY() - start.y;
RelativeLayout Rel = (RelativeLayout)findViewById(R.id.RelLayout);
//getGlobalVisibleRect(Rel);
ZoomableViewGroup ZVG = (ZoomableViewGroup) findViewById(R.id.zoomLayout);
Rel.getTop();
Rel.getY();
//if(dx > 0) dx=0;
//if(dy > 0) dy=0;
//Toast.makeText(getContext(), dx + "_" + dy + "REL=" + Rel.getTop()+"_"+ Rel.getLeft(), Toast.LENGTH_SHORT).show ();
//Toast.makeText(getContext(), ZVG.getHeight() + "-" + ZVG.getWidth(), Toast.LENGTH_SHORT).show ();
matrix.postTranslate(dx, dy);
matrix.invert(matrixInverse);
if (Math.max(Math.abs(start.x - event.getX()), Math.abs(start.y - event.getY())) > 20.f * density) {
lastDownTime = 0l;
}
} else if (mode == ZOOM) {
if (event.getPointerCount() > 1) {
float newDist = spacing(event);
if (newDist > 10f * density) {
matrix.set(savedMatrix);
float scale = (newDist / oldDist);
//to restrict the min zoom not tobe less than screen size
float[] values = new float[9];
matrix.getValues(values);
if(scale*values[matrix.MSCALE_X] <= 1)
{ scale = 1/values[matrix.MSCALE_X]; }
//till here
//condition to check maximum zoom scale to 10
if(scale * values[matrix.MSCALE_X] <10)
matrix.postScale(scale, scale, mid.x, mid.y);
matrix.invert(matrixInverse);
}
} else {
matrix.set(savedMatrix);
float scale = event.getY() / start.y;
//to restrict the min zoom to 1 or not less than screen size
float[] values = new float[9];
matrix.getValues(values);
if(scale*values[matrix.MSCALE_Y] <= 1)
{ scale = 1/values[matrix.MSCALE_Y]; }
//till here
//condition to check maximum zoom scale to 10
if(scale * values[matrix.MSCALE_Y] <10)
matrix.postScale(scale, scale, mid.x, mid.y);
matrix.invert(matrixInverse);
}
}
break;
}
invalidate();
return true;
}
}
Hope this helps . Try to Set the height and width of viewgroup dynamically.
Display display = getWindowManager().getDefaultDisplay();
ZoomableViewGroup layout= (ZoomableViewGroup) findViewById(R.id.zoomLayout);
int width=display.getWidth();
int height=display.getHeight();
FrameLayout.LayoutParams parms = new FrameLayout.LayoutParams(width,height);
layout.setLayoutParams(parms);
I have a Framelayout which add four imageview at runtime as well in center it contains main image with which user can perform different action but i face the problem with rotate layout view
currently on touch of rotate button i'm doing this
public void setRotateListener() {
mRotateImage.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
float x = event.getX(0);
float y = event.getY(0);
float theta = getTheta(x, y);
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_POINTER_DOWN:
theta_old = theta;
break;
case MotionEvent.ACTION_MOVE:
float delta_theta = theta - theta_old;
theta_old = theta;
int direction = (delta_theta > 0) ? 1 : -1;
angle += 3 * direction;
Log.d("Tag", "rotate angle : " + obj.getHeight());
obj.setRotation(angle);
notifyListener(direction);
break;
}
return true;
}
});
}
private float getTheta(float x, float y) {
float sx = x - (obj.getWidth() / 2.0f);
float sy = y - (obj.getHeight() / 2.0f);
float length = (float) Math.sqrt(sx * sx + sy * sy);
float nx = sx / length;
float ny = sy / length;
float theta = (float) Math.atan2(ny, nx);
final float rad2deg = (float) (180.0 / Math.PI);
float thetaDeg = theta * rad2deg;
return (thetaDeg < 0) ? thetaDeg + 360.0f : thetaDeg;
}
but i can't get the expected result i already refer this link as well
https://github.com/rprouse/XkcdClock
as well as try to rotate with gesture and animation too but it seems not working as per my move on the screen
I have Design A Layout that may work as your need.
Download Demo here
Java File
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class ClipArt extends RelativeLayout {
int baseh;
int basew;
int basex;
int basey;
ImageButton btndel;
ImageButton btnrot;
ImageButton btnscl;
RelativeLayout clip;
Context cntx;
boolean freeze = false;
int h;
int i;
ImageView image;
String imageUri;
boolean isShadow;
int iv;
RelativeLayout layBg;
RelativeLayout layGroup;
RelativeLayout.LayoutParams layoutParams;
public LayoutInflater mInflater;
int margl;
int margt;
float opacity = 1.0F;
Bitmap originalBitmap;
int pivx;
int pivy;
int pos;
Bitmap shadowBitmap;
float startDegree;
String[] v;
public ClipArt(Context paramContext) {
super(paramContext);
cntx = paramContext;
layGroup = this;
basex = 0;
basey = 0;
pivx = 0;
pivy = 0;
mInflater = ((LayoutInflater) paramContext.getSystemService("layout_inflater"));
mInflater.inflate(R.layout.clipart, this, true);
btndel = ((ImageButton) findViewById(R.id.del));
btnrot = ((ImageButton) findViewById(R.id.rotate));
btnscl = ((ImageButton) findViewById(R.id.sacle));
layoutParams = new RelativeLayout.LayoutParams(250, 250);
layGroup.setLayoutParams(layoutParams);
image = ((ImageView) findViewById(R.id.clipart));
image.setImageResource(R.drawable.ic_launcher);
setOnTouchListener(new View.OnTouchListener() {
final GestureDetector gestureDetector = new GestureDetector(ClipArt.this.cntx,
new GestureDetector.SimpleOnGestureListener() {
public boolean onDoubleTap(MotionEvent paramAnonymous2MotionEvent) {
return false;
}
});
public boolean onTouch(View paramAnonymousView, MotionEvent event) {
if (!ClipArt.this.freeze) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
layGroup.invalidate();
gestureDetector.onTouchEvent(event);
layGroup.performClick();
basex = ((int) (event.getRawX() - layoutParams.leftMargin));
basey = ((int) (event.getRawY() - layoutParams.topMargin));
break;
case MotionEvent.ACTION_MOVE:
int i = (int) event.getRawX();
int j = (int) event.getRawY();
layBg = ((RelativeLayout) getParent());
if ((i - basex > -(layGroup.getWidth() * 2 / 3))
&& (i - basex < layBg.getWidth() - layGroup.getWidth() / 3)) {
layoutParams.leftMargin = (i - basex);
}
if ((j - basey > -(layGroup.getHeight() * 2 / 3))
&& (j - basey < layBg.getHeight() - layGroup.getHeight() / 3)) {
layoutParams.topMargin = (j - basey);
}
layoutParams.rightMargin = -1000;
layoutParams.bottomMargin = -1000;
layGroup.setLayoutParams(layoutParams);
break;
}
return true;
}
return true;
}
});
this.btnscl.setOnTouchListener(new View.OnTouchListener() {
#SuppressLint({ "NewApi" })
public boolean onTouch(View paramAnonymousView, MotionEvent event) {
if (!ClipArt.this.freeze) {
int j = (int) event.getRawX();
int i = (int) event.getRawY();
layoutParams = (RelativeLayout.LayoutParams) layGroup.getLayoutParams();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
ClipArt.this.layGroup.invalidate();
ClipArt.this.basex = j;
ClipArt.this.basey = i;
ClipArt.this.basew = ClipArt.this.layGroup.getWidth();
ClipArt.this.baseh = ClipArt.this.layGroup.getHeight();
int[] loaction = new int[2];
layGroup.getLocationOnScreen(loaction);
margl = layoutParams.leftMargin;
margt = layoutParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
float f2 = (float) Math.toDegrees(Math.atan2(i - ClipArt.this.basey, j - ClipArt.this.basex));
float f1 = f2;
if (f2 < 0.0F) {
f1 = f2 + 360.0F;
}
j -= ClipArt.this.basex;
int k = i - ClipArt.this.basey;
i = (int) (Math.sqrt(j * j + k * k)
* Math.cos(Math.toRadians(f1 - ClipArt.this.layGroup.getRotation())));
j = (int) (Math.sqrt(i * i + k * k)
* Math.sin(Math.toRadians(f1 - ClipArt.this.layGroup.getRotation())));
k = i * 2 + ClipArt.this.basew;
int m = j * 2 + ClipArt.this.baseh;
if (k > 150) {
layoutParams.width = k;
layoutParams.leftMargin = (ClipArt.this.margl - i);
}
if (m > 150) {
layoutParams.height = m;
layoutParams.topMargin = (ClipArt.this.margt - j);
}
ClipArt.this.layGroup.setLayoutParams(layoutParams);
ClipArt.this.layGroup.performLongClick();
break;
}
return true;
}
return ClipArt.this.freeze;
}
});
this.btnrot.setOnTouchListener(new View.OnTouchListener() {
#SuppressLint({ "NewApi" })
public boolean onTouch(View paramAnonymousView, MotionEvent event) {
if (!ClipArt.this.freeze) {
layoutParams = (RelativeLayout.LayoutParams) ClipArt.this.layGroup.getLayoutParams();
ClipArt.this.layBg = ((RelativeLayout) ClipArt.this.getParent());
int[] arrayOfInt = new int[2];
layBg.getLocationOnScreen(arrayOfInt);
int i = (int) event.getRawX() - arrayOfInt[0];
int j = (int) event.getRawY() - arrayOfInt[1];
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
ClipArt.this.layGroup.invalidate();
ClipArt.this.startDegree = layGroup.getRotation();
ClipArt.this.pivx = (layoutParams.leftMargin + ClipArt.this.getWidth() / 2);
ClipArt.this.pivy = (layoutParams.topMargin + ClipArt.this.getHeight() / 2);
ClipArt.this.basex = (i - ClipArt.this.pivx);
ClipArt.this.basey = (ClipArt.this.pivy - j);
break;
case MotionEvent.ACTION_MOVE:
int k = ClipArt.this.pivx;
int m = ClipArt.this.pivy;
j = (int) (Math.toDegrees(Math.atan2(ClipArt.this.basey, ClipArt.this.basex))
- Math.toDegrees(Math.atan2(m - j, i - k)));
i = j;
if (j < 0) {
i = j + 360;
}
ClipArt.this.layGroup.setRotation((ClipArt.this.startDegree + i) % 360.0F);
break;
}
return true;
}
return ClipArt.this.freeze;
}
});
this.btndel.setOnClickListener(new View.OnClickListener() {
public void onClick(View paramAnonymousView) {
if (!ClipArt.this.freeze) {
layBg = ((RelativeLayout) ClipArt.this.getParent());
layBg.performClick();
layBg.removeView(ClipArt.this.layGroup);
}
}
});
}
public void disableAll() {
this.btndel.setVisibility(4);
this.btnrot.setVisibility(4);
this.btnscl.setVisibility(4);
}
public ImageView getImageView() {
return this.image;
}
public void setFreeze(boolean paramBoolean) {
this.freeze = paramBoolean;
}
}
Layout file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<ImageButton android:id="#+id/rotate" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:adjustViewBounds="true" android:background="#android:color/transparent" android:scaleType="fitCenter" android:src="#drawable/rotation"/>
<ImageButton android:id="#+id/sacle" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:adjustViewBounds="true" android:background="#android:color/transparent" android:scaleType="fitCenter" android:src="#drawable/pointer"/>
<ImageButton android:id="#+id/del" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:adjustViewBounds="true" android:background="#android:color/transparent" android:scaleType="fitCenter" android:src="#drawable/close"/>
<ImageView android:id="#+id/clipart" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="10dp"/>
</RelativeLayout>
and images put in drawable
I have a custom viewgroup which extends relativelayout and I have several components in side of it. Because of the bad performance of nested weight layout, I decide to set child views' size and position programmatically. For now, I use xml to create the view and subviews and then set the position and size of some of them programmatically as below.
private void assignProperSizeToChildren(int x, int y) {
int cardWidth = x / 3;
int cardHeight = y / 3;
LayoutParams layoutParams = (LayoutParams) bgView1.getLayoutParams();
layoutParams.topMargin = (int)(y / 4 * (1 - val));
layoutParams.height = cardHeight;
layoutParams.width = cardWidth;
LayoutParams layoutParams2 = (LayoutParams) bgView2.getLayoutParams();
layoutParams2.topMargin = (int)(y / 4 * (1 - val));
layoutParams2.height = cardHeight;
layoutParams2.width = cardWidth;
LayoutParams layoutParams3 = (LayoutParams) bgView3.getLayoutParams();
layoutParams3.topMargin = (int)(y * 3 / 8 * (1 - val));
layoutParams3.height = cardHeight;
layoutParams3.width = cardWidth;
bgView1.setLayoutParams(layoutParams);
bgView2.setLayoutParams(layoutParams2);
bgView3.setLayoutParams(layoutParams3);
bgView1.setPivotY(y / 2);
bgView2.setPivotY(y / 2);
bgView3.setPivotY(y / 2);
View view = findViewById(R.id.bg);
RelativeLayout.LayoutParams layoutParams1 = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams1.topMargin = y / 6;
layoutParams1.bottomMargin = y / 6;
layoutParams1.leftMargin = x / 6;
layoutParams1.rightMargin = x / 6;
view.setLayoutParams(layoutParams1);
LinearLayout.LayoutParams layoutParams4 = (LinearLayout.LayoutParams) receiveProgress.getLayoutParams();
layoutParams4.width = cardWidth;
receiveProgress.setLayoutParams(layoutParams4);
layoutParams4 = (LinearLayout.LayoutParams) sendProgress.getLayoutParams();
layoutParams4.width = cardWidth;
sendProgress.setLayoutParams(layoutParams4);
name.setTextSize(TypedValue.COMPLEX_UNIT_PX, y / 7);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int x = MeasureSpec.getSize(widthMeasureSpec);
int y = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec,heightMeasureSpec);
assignProperSizeToChildren(x,y);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
It seems to work but the view behaves strangely when I want to do an animation.
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
float val = (Float) valueAnimator.getAnimatedValue();
LayoutParams layoutParams = (LayoutParams) bgView1.getLayoutParams();
layoutParams.topMargin = (int) (getMeasuredHeight() / 4 * (1 - val));
bgView1.setLayoutParams(layoutParams);
LayoutParams layoutParams2 = (LayoutParams) bgView2.getLayoutParams();
layoutParams2.topMargin = (int) (getMeasuredHeight() / 4 * (1 - val));
bgView2.setLayoutParams(layoutParams2);
LayoutParams layoutParams3 = (LayoutParams) bgView3.getLayoutParams();
layoutParams3.topMargin = (int) (getMeasuredHeight() / 4 * (1.5 - val));
bgView3.setLayoutParams(layoutParams3);
invalidate();
}
});
I found that every time I changed the layoutparams of the child views, onMeasure() get called and the value changes. Also, the animation does not work at all. Therefore, I wonder if this is the standard(right) way to create a custom viewgroup.
Thank you very much!
I am currently in need of making ChatHeads like Facebook. Following the tutorials I found, I can make a ChatHead start from Service. However, when I added Rebound API from Facebook to make it smooth, I created a customized view like this post: Adding natural dragging effect to ImageView same as Facebook Messanger chat heads using Rebound library ;
but it seems to block every background touch. I can only drag the ChatHead around without able to touch anything else. How can I make a ChatHead that is still smooth draggable and also can interact with the background also (just the same as Facebook)? Any help is appreciated.
Thanks in advanced
BTW, this is my view
class ChatHeadView extends View implements SpringListener, SpringSystemListener {
private Spring xSpring;
private Spring ySpring;
private SpringSystem springSystem;
private final SpringConfig COASTING;
private float x;
private float y;
private boolean dragging;
private float radius = 100;
private float downX;
private float downY;
private float lastX;
private float lastY;
private VelocityTracker velocityTracker;
private float centerX;
private float centerY;
int screenWidth, screenHeight;
private Paint mPaint = new Paint();
private Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
public ChatHeadView(Context context, int width, int height) {
super(context);
springSystem = SpringSystem.create();
springSystem.addListener(this);
COASTING = SpringConfig.fromOrigamiTensionAndFriction(0, 0.5);
COASTING.tension = 0;
xSpring = springSystem.createSpring();
ySpring = springSystem.createSpring();
xSpring.addListener(this);
ySpring.addListener(this);
getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
centerX = getWidth() / 2f;
centerY = getHeight() / 2f;
xSpring.setCurrentValue(centerX).setAtRest();
ySpring.setCurrentValue(centerY).setAtRest();
getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
}
});
screenWidth = width;
screenHeight = height;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mBitmap, x - mBitmap.getWidth() / 2,
y - mBitmap.getHeight(), mPaint);
}
#SuppressLint("Recycle")
#Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getRawX();
float touchY = event.getRawY();
boolean ret = false;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downX = touchX;
downY = touchY;
lastX = downX;
lastY = downY;
velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
if (downX > x - radius && downX < x + radius && downY > y - radius
&& downY < y + radius) {
dragging = true;
ret = true;
}
break;
case MotionEvent.ACTION_MOVE:
if (!dragging) {
break;
}
velocityTracker.addMovement(event);
float offsetX = lastX - touchX;
float offsetY = lastY - touchY;
xSpring.setCurrentValue(xSpring.getCurrentValue() - offsetX)
.setAtRest();
ySpring.setCurrentValue(ySpring.getCurrentValue() - offsetY)
.setAtRest();
checkConstraints();
ret = true;
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
if (!dragging) {
break;
}
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
dragging = false;
ySpring.setSpringConfig(COASTING);
xSpring.setSpringConfig(COASTING);
downX = 0;
downY = 0;
xSpring.setVelocity(velocityTracker.getXVelocity());
ySpring.setVelocity(velocityTracker.getYVelocity());
ret = true;
}
lastX = touchX;
lastY = touchY;
return ret;
}
#Override
public void onSpringUpdate(Spring s) {
x = (float) xSpring.getCurrentValue();
y = (float) ySpring.getCurrentValue();
invalidate();
}
#Override
public void onSpringActivate(Spring s) {
}
#Override
public void onSpringAtRest(Spring s) {
}
#Override
public void onSpringEndStateChange(Spring s) {
}
#Override
public void onBeforeIntegrate(BaseSpringSystem springSystem) {
}
#Override
public void onAfterIntegrate(BaseSpringSystem springSystem) {
checkConstraints();
}
private void checkConstraints() {
if (x + radius >= screenWidth) {
xSpring.setVelocity(-xSpring.getVelocity());
xSpring.setCurrentValue(xSpring.getCurrentValue()
- (x + radius - screenWidth), false);
}
if (x - radius <= 0) {
xSpring.setVelocity(-xSpring.getVelocity());
xSpring.setCurrentValue(xSpring.getCurrentValue() - (x - radius),
false);
}
if (y + radius >= screenHeight) {
ySpring.setVelocity(-ySpring.getVelocity());
ySpring.setCurrentValue(ySpring.getCurrentValue()
- (y + radius - screenHeight), false);
}
if (y - radius <= 0) {
ySpring.setVelocity(-ySpring.getVelocity());
ySpring.setCurrentValue(ySpring.getCurrentValue() - (y - radius),
false);
}
}
}
this is where I add View with WindowManager:
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
screenWidth = size.x;
screenHeight = size.y;
chatHeadView = new ChatHeadView(this, screenWidth, screenHeight);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, PixelFormat.TRANSLUCENT);
windowManager.addView(chatHeadView, params);
In the documentation WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
Window flag: even when this window is focusable (its FLAG_NOT_FOCUSABLE is not set), allow any pointer events outside of the window to be sent to the windows behind it. Otherwise it will consume all pointer events itself, regardless of whether they are inside of the window.
It's saying about your problem.
Instead, try WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE flag.
you can get TouchEvent on the view and it won't consume other events.
I want to move and scale the view on the right while dragging it to left side.I tried to set the layout parameters of this view on touch.It moved and scaled the view.But rendering is not correct when moving our finger fastly to both left and right sides.
This view on the right side is a custom layout extends LinearLayout having a ListView as child.And the left side is also another layout and integrated both layouts into a Framelayout(similar to slidingmenu).
Is there any way to render the layout (move and scale) the view without updating LayoutParams?
Is it possible to update the layout using canvas and matrix?
Here is the code for custom layout for view on the right side(the small view).
public class SlidingLayout extends LinearLayout {
private static String LOG_TAG = "SlidingLayout";
private boolean isTranformed = false;
private PanGestureListener gestureListener;
private GestureDetector gestureDetector;
private boolean isAnimating = false;
private boolean isScrolling = false;
private DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
private Matrix matrix = new Matrix();
private float posX = 0;
private float posY = 0;
public CustomSlidingLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
private void init(Context context){
gestureListener = new PanGestureListener();
gestureDetector = new GestureDetector(context, gestureListener);
matrix.setTranslate(0, 0);
matrix.setScale(1.0f, 1.0f);
}
#Override
protected void onDraw(Canvas canvas) {
//canvas.save();
/*canvas.drawColor(Color.RED);
canvas.translate(posX, posY);
super.onDraw(canvas);*/
/*canvas.restore();
matrix.reset();
matrix = canvas.getMatrix();*/
/*if (isTranformed) {
matrix.postTranslate(posX, posY);
canvas.setMatrix(matrix);
}
super.onDraw(canvas);*/
}
private void makeViewSmall() {
if (!isAnimating) {
isAnimating = true;
Rect rect = new Rect();
getLocalVisibleRect(rect);
ResizeMoveAnimation anim = new ResizeMoveAnimation(this,
(int) (displayMetrics.widthPixels * 0.8), displayMetrics.heightPixels / 4,
displayMetrics.widthPixels * 2, rect.bottom - displayMetrics.heightPixels
/ 4);
anim.setAnimationListener(animationListener);
anim.setDuration(1000);
anim.setInterpolator(new BounceInterpolator());
startAnimation(anim);
}
}
public void makeViewOriginal() {
if(isTranformed){
if (!isAnimating) {
isAnimating = true;
ResizeMoveAnimation anim = new ResizeMoveAnimation(this, 0, 0,
displayMetrics.widthPixels, displayMetrics.heightPixels);
anim.setAnimationListener(animationListener);
anim.setInterpolator(new BounceInterpolator());
anim.setDuration(1000);
startAnimation(anim);
}
}else{
makeViewSmall();
}
}
private AnimationListener animationListener = new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) CustomSlidingLayout.this .getLayoutParams();
if (isTranformed) {
isTranformed = false;
params.leftMargin = 0;
params.topMargin = 0;
params.width = displayMetrics.widthPixels;
params.height = displayMetrics.heightPixels;
requestLayout();
} else {
isTranformed = true;
}
isAnimating = false;
}
};
class PanGestureListener extends GestureDetector.SimpleOnGestureListener {
#Override
public boolean onSingleTapConfirmed(MotionEvent event) {
if (isTranformed) {
makeViewOriginal();
return true;
}
return false;
}
}
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (isTranformed) {
return true;
} else {
return false;
}
}
private int _xDelta = 0;
private int _yDelta = 0;
#Override
public boolean onTouchEvent(MotionEvent event) {
//gestureDetector.onTouchEvent(event);
if (isTranformed) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
this.requestLayout();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this .getLayoutParams();
if (layoutParams.leftMargin == 0 && layoutParams.topMargin == 0) {
//this.requestLayout();
isTranformed = false;
isScrolling = false;
break;
}
isScrolling = true;
int xDiff = layoutParams.leftMargin - (X - _xDelta);
layoutParams.leftMargin = X - _xDelta;
int scaleFactor = layoutParams.leftMargin > 0 ? layoutParams.leftMargin : 1;
layoutParams.topMargin = layoutParams.topMargin - ((layoutParams.topMargin / scaleFactor) * xDiff);
if (layoutParams.leftMargin < 0) {
layoutParams.leftMargin = 0;
}
if (layoutParams.topMargin < 0) {
layoutParams.topMargin = 0;
}
layoutParams.width = (displayMetrics.widthPixels - layoutParams.leftMargin);
layoutParams.height = (displayMetrics.heightPixels - (layoutParams.topMargin * 2));
this.requestLayout();
/*final float dx = X - _xDelta;
final float dy = Y - _yDelta;
posX += dx;
posY += dy;
//matrix.postScale(scaleFactor, scaleFactor,0.0f,0.5f);
Bitmap bitmap = Bitmap.createBitmap((int)(displayMetrics.widthPixels - posX), (int)(displayMetrics.heightPixels - posY), Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
matrix.postTranslate(posX, posY);
canvas.setMatrix(matrix);
this.draw(canvas);
_xDelta = X;
_yDelta = Y;
invalidate();*/
break;
case MotionEvent.ACTION_UP:
isScrolling = false;
break;
case MotionEvent.ACTION_DOWN:
FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) this
.getLayoutParams();
_xDelta = X - lParams.leftMargin;
_yDelta = X - lParams.topMargin;
posX = 0;
posY = 0;
break;
}
return true;
}
return true;
}
}
You can call invalidate() in onTouch() to execute the code in onDraw() to redraw the view.
invalidate() will force a view to draw.