I am a newbie and I want to use this example (example number 3) in my app.
My app will do some calculations at background and the result will be 0, 1, 2, 3, or 4. How should I make the needle move accordingly (needle should move left to right)?
Based on the output, you could use the code from this video: https://www.youtube.com/watch?v=tWCHDoO14aE to rotate the needle image a certain number of degrees to get to the value on the gauge
I didnt try but it must work. change stroke_colors attr as below to get proper coloring as in your image above. There are seven color segments so 1 segment means max_val/7
<FrameLayout
android:layout_width="260dp"
android:layout_height="162dp"
android:background="#354051">
<com.sccomponents.widgets.ScArcGauge
android:id="#+id/gauge"
xmlns:sc="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:padding="30dp"
sc:scc_angle_start="-180"
sc:scc_angle_sweep="180"
sc:scc_stroke_colors="#F7AD36|#8BBE28|#8BBE28|#F7AD36|#F7AD36|#EC4949|#EC4949"
sc:scc_stroke_colors_mode="solid"
sc:scc_stroke_size="30dp"/>
<ImageView
android:id="#+id/indicator"
android:layout_width="64dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="29dp"
android:layout_marginLeft="18dp"
android:src="#drawable/indicator"/>
</FrameLayout>
float angle0 = 0;
float angle1 = gauge.percentageToAngle(max_val/7);
float angle2 = gauge.percentageToAngle(max_val/7*3);
float angle3 = gauge.percentageToAngle(max_val/7*5);
float angle4 = gauge.percentageToAngle(max_val);
float angle;
if(cur_val >= 0 && cur_val < max_val/7)
angle = angle0;
else if(cur_val >= max_val/7 && cur_val < max_val/7*3)
angle = angle1;
else if(cur_val >= max_val/7*3 && cur_val < max_val/7*5)
angle = angle2;
else if(cur_val >= max_val/7*5 && cur_val < max_val)
angle = angle3;
else
angle = angle4;
indicator.setRotation(angle);
Related
I implemented ACTION_MOVE for ImageView which is bigger then its parent (FrameLayout). Now I'm trying to add some code to stop movement (both drag and pinch zooming) when at least one of Image edges is inside its parent (so it won’t show background of a parent).
I used the code like in this question.
case MotionEvent.ACTION_MOVE:
if (mode == DRAG) { //movement of first finger
matrix.set(savedMatrix);
float newX = event.getX() - start.x;
float newY = event.getY() - start.y;
if (view.getLeft() >= -392){
matrix.postTranslate(newX, newY);
}
}
else if (mode == ZOOM) { //pinch zooming
float[] f = new float[9];
float newDist = spacing(event);
if (newDist > 5f) {
matrix.set(savedMatrix);
scale = newDist / oldDist;
matrix.postScale(scale, scale, mid.x, mid.y);
}
matrix.getValues(f);
float scaleX = f[Matrix.MSCALE_X];
float scaleY = f[Matrix.MSCALE_Y];
if(scaleX <= MIN_ZOOM) {
matrix.postScale((MIN_ZOOM)/scaleX,
(MIN_ZOOM)/scaleY, mid.x, mid.y);
}
else if(scaleX >= MAX_ZOOM) {
matrix.postScale((MAX_ZOOM)/scaleX,
(MAX_ZOOM)/scaleY, mid.x, mid.y);
}
}
break;
I tried many things, and I know similar questions had been asked already but non of them fit my need so far.
My best guess was to add code below but it looks like mImageView.getLeft(), mImageView.getRight() etc returns parents edges not the images.
In onCreate():
DisplayMetrics displayMetrics =
getApplicationContext().getResources().getDisplayMetrics();
float screenWidth = displayMetrics.widthPixels;
float screenHeight = displayMetrics.heightPixels;
and in case MotionEvent.ACTION_MOVE
if (mImageView.getLeft() > 0 ||
mImageView.getRight() < screenWidth) {
matrix.postTranslate(0, newY);
break;
}
else if (mImageView.getTop() > 0 ||
mImageView.getBottom() < screenHeight) {
matrix.postTranslate(newX, 0);
break;
}
else {
matrix.postTranslate(newX, newY);
}
And this is my layout:
<RelativeLayout
android:id="#+id/imageViewContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/mag_background">
<TextView/>
<ImageView/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/imageViewHeadingLabel">
<ImageView
android:id="#+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/image"
android:scaleType="matrix"
android:layout_gravity="center_vertical|center_horizontal"
android:contentDescription="image to zoom"/>
</FrameLayout>
</RelativeLayout>
Thanks in advance for your help!
I found solution hire.
I reverse the checks so instead of not letting image to move outside layout I not letting image bounds to be move inside layout like this:
if (mode == DRAG) { //movement of first finger
matrix.set(savedMatrix);
matrix.getValues(matrixValues);
matrixX = matrixValues[2];
matrixY = matrixValues[5];
width = matrixValues[0] * (view.getDrawable().getIntrinsicWidth());
height = matrixValues[4] * (view.getDrawable().getIntrinsicHeight());
dx = event.getX() - start.x;
dy = event.getY() - start.y;
//if image will go inside left bound
if (matrixX + dx > 0){
dx = -matrixX;
}
//if image will go inside right bound
if(matrixX + dx + width < view.getWidth()){
dx = view.getWidth() - matrixX - width;
}
//if image will go inside top bound
if (matrixY + dy > 0){
dy = -matrixY;
}
//if image will go inside bottom bound
if(matrixY + dy + height < view.getHeight()){
dy = view.getHeight() - matrixY - height;
}
matrix.postTranslate(dx, dy);
}
However if you move zoomed image to the corner and then zoom out, it will show parent background until next touch event so problem is not fully solved.
I am creating a game, where there will be a lot of clickable ImageView(s), and one unclickable imageView, when the clickable ImageView is clicked, it should swap its position with the unclickable ImageView (in this example, its called imageView2).
Everything works fine when I am using px unit for my imageView(s). However, as you know using px units will resulted in different display on different devices. However, the property animations does not work when I use dp units. How do I get it working with dp units ??
MainActivity.java
public class MainActivity extends Activity implements View.OnClickListener {
ImageView imageView1, imageView2;
float x, x_9, y, y_9;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView1 = (ImageView) findViewById(R.id.imageView1);
imageView2 = (ImageView) findViewById(R.id.imageView2);
imageView1.setOnClickListener(this);
}
#Override
public void onClick(View v) {
// Get x position of clicked imageView
x = v.getX();
// Get x position of imageView2
x_9 = imageView2.getX();
// Get y position of clicked imageView
y = v.getY();
// Get y position of imageView2
y_9 = imageView2.getY();
// Check if imageViews are align with each other either horizontally or vertically
if((x == x_9 && y + 100 == y_9) || (x == x_9 && y - 100 == y_9) || (x + 100 == x_9 && y == y_9) || (x - 100 == x_9 && y == y_9)) {
// If they are aligned, swap their position with property animation
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", x_9);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("translationY", y_9);
PropertyValuesHolder pvhX9 = PropertyValuesHolder.ofFloat("translationX", x);
PropertyValuesHolder pvhY9 = PropertyValuesHolder.ofFloat("translationY", y);
ObjectAnimator blockAnim = ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY);
blockAnim.setDuration(500);
blockAnim.setRepeatCount(0);
blockAnim.start();
ObjectAnimator blockAnim2 = ObjectAnimator.ofPropertyValuesHolder(imageView2, pvhX9, pvhY9);
blockAnim2.setDuration(500);
blockAnim2.setRepeatCount(0);
blockAnim2.start();
}
}
}
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<RelativeLayout
android:id="#+id/relative"
android:background="#color/grey"
android:layout_width="400dp"
android:layout_height="400dp"
>
<ImageView
android:id="#+id/imageView1"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/smiley1"/>
<ImageView
android:id="#+id/imageView2"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#drawable/smiley2"
android:translationX="100dp"/>
</RelativeLayout>
</RelativeLayout>
How do I work around this problem ? All suggestions are greatly welcomed. Thank you.
As suggested by Nikola Milutinovic, I added GlobalLayoutListener like below
this.findViewById(R.id.relative).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
x = v.getX();
x_9 = imageView2.getX();
y = v.getY();
y_9 = imageView2.getY();
}
});
I think the way to do it is to change your hard coded referece to the width and height by the actual value contained by the imageViews. In your if condition change 100 to getHeight() or getWidth();
int height = imageView1.getHeight();
int width = imageView1.getWidth();
if((x == x_9 && y + height == y_9) || (x == x_9 && y - height == y_9) ||
(x + width == x_9 && y == y_9) || (x - width == x_9 && y == y_9)){
}
This way you do not have a reference to px. The "100" value that your were using meant 100px. The real width or height for an hdpi device would of been something like 1.5*100 = 150px. By using getWidth() and getHeight(), you are using the actual value of px in your screen. I hope it is clear. You will need to modify your if condition for more than 2 imageViews, but the principle is the same.
Finally it is better to use AnimatorSet if you want your animations to be synchronized.
ArrayList <Animator> animations = new ArrayList<Animator>();
animations.add(ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY));
animations.add(ObjectAnimator.ofPropertyValuesHolder(imageView2, pvhX9, pvhY9));
AnimatorSet animatoreSet = new AnimatorSet();
animatorSet.setDuration(500);
animatorSet.setRepeatCount(0);
animatorSet.playTogether(animations);
animatorSet.start();
By doing this if you need to add listeners you just add them once.
See documentation for these two methods below and find which one suits you the most. container would be your root layout (this RelativeLayout at the top or this with id relative)
container.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
}
});
container.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
#Override
public void onDraw() {
}
});
Here is the example of my implementation of this listener.
I do all sorts of stuff inside. Please take a look.
public class CustomOnGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
private Context context;
private View fragment;
private float x1;
private float y1;
private float x2;
private float y2;
public CustomOnGlobalLayoutListener(Context context, View view, float x1, float y1, float x2, float y2) {
this.context = context;
this.fragment = view;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
}
#Override
public void onGlobalLayout() {
fragment.setX(x1);
fragment.setY(y1);
removeOnGlobalLayoutListener();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) fragment.getLayoutParams();
fragment.setLayoutParams(layoutParams);
fragment.setPivotX(0);
fragment.setPivotY(0);
fragment.setScaleX((x2 - x1) / fragment.getMeasuredWidth());
fragment.setScaleY((y2 - y1) / fragment.getMeasuredHeight());
fragment.setAlpha(0f);
PropertyValuesHolder pA = PropertyValuesHolder.ofFloat(View.ALPHA, 1f);
PropertyValuesHolder pX = PropertyValuesHolder.ofFloat(View.X, 0f);
PropertyValuesHolder pY = PropertyValuesHolder.ofFloat(View.Y, 0f);
PropertyValuesHolder pSx = PropertyValuesHolder.ofFloat(View.SCALE_X, 1);
PropertyValuesHolder pSy = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1);
final ObjectAnimator animator1 = ObjectAnimator.ofPropertyValuesHolder(fragment, pA, pX, pY, pSx, pSy);
animator1.setInterpolator(new AccelerateDecelerateInterpolator());
animator1.setDuration(200);
animator1.start();
}
private void removeOnGlobalLayoutListener() {
if (Build.VERSION.SDK_INT < 16) {
//noinspection deprecation
fragment.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
fragment.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
}
DO NOT FORGET TO REMOVE GLOBAL LAYOUT LISTENER;
If you have any problem implementing this, write and we will think something out :)
You can also check my github repo where I am actually using this to achieve opening fragment with viewpager from point of touch.
https://github.com/mrnmilutinovic/HumanityTestProject
Check ImagePagerFragment class to see it's usage.
This code is compilable, so you can also run and see that it works.
I'm pretty new to Android and I'm really struggling trying to understand what is going on in my application.
I'm trying to build a small game in which a circle appears on the screen, in a random position and it disappears as soon as the user clicks on it. Then a new circle appears in another position.
The problem is that comparing the coordinates of the user's click, and the coordinates of the center of the circle, these seem to be totally different…
The problem seems to be in the circle coordinates, because if I try to force its position to the center of the view, it appears in a totally wrong position, at the right bottom of the view.
What am I doing wrong?
This is the code of the function drawing the circles in the view (which is as big as its parent).
public void drawDots(){
Paint paint = new Paint();
paint.setColor(Color.MAGENTA);
Bitmap bg = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
View ll = (View) findViewById(R.id.circle);
ll.setBackground(new BitmapDrawable(bg));
centerX = rand.nextInt(ll.getWidth());
centerY = rand.nextInt(ll.getHeight());
Canvas canvas = new Canvas(bg);
canvas.drawCircle(centerX, centerY, radius, paint);
Log.i("Point center X :" + centerX, " Y " + centerY);
ll.setOnTouchListener(new View.OnTouchListener() {
int x = 0, y = 0;
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
x = (int) event.getX();
y = (int) event.getY();
Log.i("CLICK X: " + x, "click Y: " + y);
if((x < (centerX + radius) && x > (centerX - radius))) && ((y > centerY + radius) && (y < centerY - radius)) ){
Log.i("x ok: " + x + " y ok: " + y, "Counter: " + counter);
drawDots();
}else{
Log.i("x NOT ok " + x, " Circle area between: " + (centerX-radius) + " e " + (centerX + radius));
Log.i("Y NOT ok " + y, " Circle area between: " + (centerY-radius) + " e " + (centerY + radius));
}
}
return true;
}
});
}
And this is the layout. The textview and the button are needed to start a timer but they are removed from the layout as soon as the user clicks on the start button.
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<TextView
android:id="#+id/timerValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginBottom="37dp"
android:textSize="40sp"
android:textColor="#ffffff"
android:text="#string/timerVal" />
<Button
android:id="#+id/startButton"
android:layout_width="90dp"
android:layout_height="45dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="38dp"
android:text="#string/startButtonLabel" />
<View android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/circle"/>
Sorry for my bad explanation but I even dunno where the problem is.
EDIT I tried this solution and it actually seems to improve the situation but if i only consider the x-axis, for the y-axis there is any correspondence but in this way it seems the coordinates of the click are totally out of range... Circle drawn on canvas doesn't match the screen
even though i actually don't understand WHY it is needed
The problem is here:
centerX = rand.nextInt(ll.getWidth());
ll.getWidth() returns you 0 and rand.nextInt() won't work
when ll.getWidth() is 0.
so cannot call nextInt(0). Check out Random#nextInt().
to fix this make a check:
if(ll.getWidth() == 0)
centerX = 0;
else
centerX = rand.nextInt(ll.getWidth());
But I'm not certain what you are doing so hopefully you will find a better solution.
P.S - same you have to do with the other case, I still doubt what is the need of rand.nextInt(ll.getWidth());. (you may edit your question and make clear what you want to achieve)
as a newbie you code is nice enough to gain upvotes :)
~happycoding
I finally figured out the problem, which was here:
Bitmap bg = Bitmap.createBitmap(480, 800, Bitmap.Config.ARGB_8888);
with this call i was specifying a view of 480px of width and 800px of height, whereas my view is occupying the entire parent view (which is the screen).
This was a quite a newbie mistake, but i hope it could help someone else as i've been struggling for two days with it! :)
Hello I have two images and i am merging that images using canvas
here is the below code
Intent intent = getIntent();
//bm is the image get from camera
bm = BitmapFactory.decodeFile(intent.getStringExtra("getdata"));
//this is simple white text image
bm1 = BitmapFactory.decodeResource(getResources(), R.drawable.txt_made_hawk_nelson);
imgSeletedPhoto = (ImageView) findViewById(R.id.imgSelectedPhoto);
int width = bm.getWidth();
int height = bm.getHeight();
int maxWidth = (width > bm1.getWidth() ? width : bm1.getWidth());
int maxHeight = (height > bm1.getHeight() ? height : bm1.getHeight());
// calculate the scale - in this case = 0.4f
float scaleWidth = ((float) maxWidth) / width;
float scaleHeight = ((float) maxHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
bmOverlay = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);
Canvas canvas = new Canvas(bmOverlay);
//canvas.drawBitmap(bm, 0, 0, null);
canvas.drawBitmap(bm1, 0, 50, null);
imgSeletedPhoto.setImageBitmap(bmOverlay);
} catch (Exception e) {
e.printStackTrace();
}
i want to scale image and image should look like below
but instead of by doing above code it is looking like
XML code of this file is
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:weightSum="10" >
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="7" > // this is covering 70% of screen
<ImageView
android:id="#+id/imgSelectedPhoto"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:background="#baca9d"
android:gravity="center"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp" >
can any body help me how to stretch image and make it full from bottom and top side also and put text in center
int targetWidth = 70% of screen width;
int targetHeight = 70% of screen height;
int saclex = (int)((float)targetWidth / (float)bmp1.getWidth());
int sacley = (int)((float)targetHeight / (float)bmp1.getHeight());
apply scale values to bmp1 and create scaled bitmap
saclex = (int)((float)targetWidth / (float)bmp.getWidth());
sacley = (int)((float)targetHeight / (float)bmp.getHeight());
apply scale values bmp and create scaled bitmap. Hope this will help. or else you can use this method to create it.
Bitmap bitmap = Bitmap.createScaledBitmap(mTargetImage, bWidth,
bHeight, false);
I need to find an algorithm which determines a relationship between a square and rectangle. It must be able to determine if:
The square is completely inside the rectangle
The square is partially inside (overlaps) the rectangle
Square's corner only touches a rectangle's corner
Square's edge is on the rectangle's edge
And here are the inputs (given values) that will help us to extract a mathematical formula for each case:
x coordinate of the center of the square = squareX
y coordinate of the center of the square = squareY
width of the square = squareW
x coordinate of the center of the rectangle = recX
y coordinate of the center of the rectangle = recY
width of the rectangle = recW
length of the rectangle = recL
P.S: Rectangle's sizes are always bigger than the square's width.
I will write the code in Java once we can extract an algorithm using mathematical operations.
Edit:
For the case of corners in touch, here is the code I wrote, and it works (Math.abs means the absolute value):
((Math.abs(Math.abs(recX-squareX)-(recW+squareW)/2))<=0.001) && ((Math.abs(Math.abs(recY-squareY)-(recL+squareW)/2))<=0.001)
updated for doubles
double dx = Math.abs(rectX - squareX);
double dy = Math.abs(rectY - squarey);
double dw2 = (rectW + squareW) / 2;
double dh2 = (rectL + squareW) / 2;
if (Double.compare(dx, dw2) == 0 && Double.compare(dy, dh2) == 0)
return CORNER_TOUCH;
else if (Double.compare(dx, dw2) > 0 || Double.compare(dy, dh2) > 0)
return OUTSIDE;
else if (Double.compare(dx, dw2) == 0 || Double.compare(dy, dh2) == 0)
return EDGE_TOUCH;
else if (Double.compare(dx, rectW - dw2) <= 0 &&
Double.compare(dy, rectL - dh2) <= 0)
return INSIDE;
else
return OVERLAPS;
squareX1 = squareX - squareW/2
squareY1 = squareY - squareW/2
squareX2 = squareX + squareW/2
squareY2 = squareY + squareW/2
recX1 = recX - recW/2
recY1 = recY - recL/2
recX2 = recX + recW/2
recY2 = recY + recL/2
inside = squareX1 > recX1 && squareX2 < recX2 && squareY1 > recY1 && squareY2 < recY2
overlaps = squareX1 < recX2 && squareX2 > recX1 && squareY1 < recY2 && squareY2 > recY1
the last two one should be trivial