android Layout design dynamically - android

I am trying to design ui part in android ...there is one layout which hold an image..and go for another view which create element dynamically on same layout...my dynamic layout works well but static one not show...In short I want dynamic one on static layout with the image. My code is:
public class CircleView extends RelativeLayout {
static final int centerId = 100;
static final int center = 110;
private final int radius;
ImageView image=new ImageView(getContext());
private RelativeLayout.LayoutParams createNewRelativeLayoutParams() {
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
//image.setLayoutParams(lp);
lp.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
//image.setImageResource(R.drawable.info);
//image.setLayoutParams(lp);
lp.addRule(RelativeLayout.ABOVE, centerId);
lp.addRule(RIGHT_OF, centerId);
return lp;
}
private View prepareElementForCircle(View elem, int distX, int distY) {
RelativeLayout.LayoutParams lp = createNewRelativeLayoutParams();
elem.measure(0, 0);
int deltaX = elem.getMeasuredWidth() / 2;
int deltaY = elem.getMeasuredHeight() / 2;
lp.setMargins(distX - deltaX, 0, 0, radius - distY - deltaY);
elem.setLayoutParams(lp);
return elem;
}
public CircleView(Context context, int radius, View[] elements) {
super(context);
this.radius = radius;
/*RelativeLayout.LayoutParams lpView = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
this.setLayoutParams(lpView);*/
View center = new View(context);
center.setId(centerId);
RelativeLayout.LayoutParams lpcenter = new RelativeLayout.LayoutParams(
0, 0);
lpcenter.addRule(CENTER_HORIZONTAL);
lpcenter.addRule(CENTER_VERTICAL);
center.setLayoutParams(lpcenter);
//center.setBackgroundResource(R.drawable.info);
this.addView(center);
//ImageView tt=new ImageView(this);
this.addView(prepareElementForCircle(elements[0], 0, 0));
if (elements.length % 2 == 0) {
this.addView(prepareElementForCircle(elements[elements.length / 2],
0, 2 * radius));
}
if (elements.length > 2) {
for (int i = 1; i <= (elements.length - 1) / 2; i++) {
int y = i * 4 * radius / elements.length;
int x = (int) Math.sqrt(Math.pow(radius, 2)
- Math.pow((radius - y), 2));
this.addView(prepareElementForCircle(elements[i], x, y));
this.addView(prepareElementForCircle(elements[elements.length
- i], -x, y));
}
}
}
}

Related

Semi circular menu with elements facing towards center

I need a semi circular menu for my app .
I have been using this library to achieve the same :-
https://github.com/xresco/CircularLayout
I am able to achieve something like this:-
As you can see the Library works well for circular layout , however for rectangular layouts , not so good.
The code which handles the rotation of the rectangles is as follows:-
#Override
#SuppressWarnings("deprecation")
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int childs = getChildCount();
float totalWeight = 0f;
for(int i=0; i<childs; i++) {
final View child = getChildAt(i);
LayoutParams lp = layoutParams(child);
totalWeight += lp.weight;
}
shiftAngle= mAngleRange/totalWeight;
final int width = getWidth();
final int height = getHeight();
final float minDimen = width > height ? height : width;
float radius = (minDimen )/2f;
radius=(float) (width/2)+radius_parameter;
float startAngle = mAngleOffset+270;
for(int i=0; i<childs; i++) {
final View child = getChildAt(i);
final LayoutParams lp = layoutParams(child);
final float angle = mAngleRange/totalWeight * lp.weight;
final float centerAngle = startAngle ;
final int x;
final int y;
Log.e("CenterAngle", String.valueOf(centerAngle));
if(child instanceof CircularLayoutItem)
{
CircularLayoutItem civ=(CircularLayoutItem)child;
civ.setRotationParameters((int)(centerAngle)+90);
}
if(childs > 1) {
x = (int) (radius * Math.cos(Math.toRadians(centerAngle))) + width/2+center_width_parameter;
y = (int) (radius * Math.sin(Math.toRadians(centerAngle))) + height/3+(int)radius+center_height_parameter;
} else {
x = width/2;
y = height/2;
}
final int halfChildWidth = child.getMeasuredWidth()/2;
final int halfChildHeight = child.getMeasuredHeight()/2;
final int left = lp.width != LayoutParams.FILL_PARENT ? x - halfChildWidth : 0;
final int top = lp.height != LayoutParams.FILL_PARENT ? y - halfChildHeight : 0;
final int right = lp.width != LayoutParams.FILL_PARENT ? x + halfChildWidth : width;
final int bottom = lp.height != LayoutParams.FILL_PARENT ? y + halfChildHeight : height;
Log.e("Coords", String.valueOf(left)+"/"+right+"/"+top+"/"+bottom);
child.layout(left, top, right, bottom);
startAngle += angle;
}
invalidate();
}
Is there a way so that the rectangles appear as whole and still facing to the center?
I have come here from here:-
Horizontal Curved Sliding menu
Any help is appreciated.Thank you.

What's the standard way of set child views' size and position?

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!

Move and scale custom view in android

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();

How to redraw a layout using canvas and matrix in android?

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.

measure all child views of RelativeView before drawing

I have method, which should create a Bitmap from the RelativeLayout. My RelativeLayout creates dynamically and place all input Views into the circle. It looks like this:
public class CircleView extends RelativeLayout {
static final int centerId = 111;
private final int radius;
Bitmap returnedBitmap;
private RelativeLayout.LayoutParams createNewRelativeLayoutParams() {
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.ABOVE, centerId);
lp.addRule(RIGHT_OF, centerId);
return lp;
}
private View prepareElementForCircle(View elem, int distX, int distY) {
RelativeLayout.LayoutParams lp = createNewRelativeLayoutParams();
elem.measure(0, 0);
int deltaX = elem.getMeasuredWidth() / 2;
int deltaY = elem.getMeasuredHeight() / 2;
lp.setMargins(distX - deltaX, 0, 0, radius - distY - deltaY);
elem.setLayoutParams(lp);
return elem;
}
public CircleView(Context context, int radius, View[] elements) {
super(context);
this.radius = radius;
RelativeLayout.LayoutParams lpView = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
this.setLayoutParams(lpView);
View center = new View(context);
center.setId(centerId);
RelativeLayout.LayoutParams lpcenter = new RelativeLayout.LayoutParams(
0, 0);
lpcenter.addRule(CENTER_HORIZONTAL);
lpcenter.addRule(CENTER_VERTICAL);
center.setLayoutParams(lpcenter);
this.addView(center);
this.addView(prepareElementForCircle(elements[0], 0, 0));
if (elements.length % 2 == 0) {
this.addView(prepareElementForCircle(elements[elements.length / 2],
0, 2 * radius));
}
if (elements.length > 2) {
for (int i = 1; i <= (elements.length - 1) / 2; i++) {
int y = i * 4 * radius / elements.length;
int x = (int) Math.sqrt(Math.pow(radius, 2)
- Math.pow((radius - y), 2));
this.addView(prepareElementForCircle(elements[i], x, y));
this.addView(prepareElementForCircle(elements[elements.length
- i], -x, y));
}
}
}
When I pass several views into my CircleView and setContentView of it, everything works fine. But I need also implement ability to rotate this CircleView. So I need to convert my RelativeLayout to the Bitmap. I do it like this:
public Bitmap getBitmapFromView() {
this.measure(MeasureSpec.makeMeasureSpec(createNewRelativeLayoutParams().width, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(createNewRelativeLayoutParams().height, MeasureSpec.UNSPECIFIED));
this.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight());
this.setGravity(Gravity.CENTER);
Bitmap returnedBitmap = Bitmap.createBitmap(this.getMeasuredWidth(), this.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
this.draw(c);
return returnedBitmap;
}
as a result I've got my view, but it looks like ugly. So not every view displays and they are not in circle. So my guess is what measuring of the View acts not like it should to be. Maybe, I should to measure all the children? Or maybe call Bitmap convertion method in onPreDraw()? I've tried both of solutions but they didn't work for me.
I solved this by
public Bitmap getBitmapFromView() {
DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics();
this.measure(MeasureSpec.makeMeasureSpec(dm.widthPixels, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(dm.heightPixels, MeasureSpec.EXACTLY));
this.layout(0, 0, this.getMeasuredWidth(), this.getMeasuredHeight());
this.setGravity(Gravity.CENTER);
Bitmap returnedBitmap = Bitmap.createBitmap(this.getMeasuredWidth(),
this.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(returnedBitmap);
this.draw(c);
return returnedBitmap;
}
so DisplayMetrics solved my problem.

Categories

Resources