I'm trying to make a frame for TextView as a cloud. But the content area does not behave as expected. What am i doing wrong?
I have a suggestion that is not working properly because the content area less scale area. So sad. I remade it to handle 9-patch manually. Save pictures without .9.png. Get Bitmap. There are 9-line present. With getPixels calculated padding and set it on the TextView. After that calculating and set LayoutParams.width and LayoutParams.height. Looks a bit ugly, but it works quite quickly, and most importantly correctly.
private int startX=-1;
private int endX=-1;
private int contentW=-1;
private int contentH=-1;
Bitmap bmp=BitmapFactory.decodeResource(getResources(), mIconResId);
int[] pixels=new int[bmp.getWidth()*bmp.getHeight()];
bmp.getPixels(pixels, 0, bmp.getWidth(), 0, 0, bmp.getWidth(),bmp.getHeight());
for(int i=0;i<bmp.getWidth();i++){
if(startX==-1 && pixels[bmp.getWidth()*(bmp.getHeight()-1)+i]==Color.BLACK){
startX=i;
}
if(startX!=-1 && pixels[bmp.getWidth()*(bmp.getHeight()-1)+i]!=Color.BLACK){
endX=i;
break;
}
}
int startY=-1;
int endY=-1;
for(int i=0;i<bmp.getHeight();i++){
if(startY==-1 && pixels[bmp.getWidth()*(i+1)-1]==Color.BLACK){
startY=i;
}
if(startY!=-1 && pixels[bmp.getWidth()*(i+1)-1]!=Color.BLACK){
endY=i;
break;
}
}
setBackground(new BitmapDrawable(getResources(),Bitmap.createBitmap(bmp, 1, 1, bmp.getWidth()-2, bmp.getHeight()-2)));
contentW=endX-startX;
endX=bmp.getWidth()-endX;
contentH=endY-startY;
endY=bmp.getHeight()-endY;
new Handler().post(new Rannable(){
#Override
public void run() {
int w=textview.getWidth();
int h=textview.getHeight();
if(w>endX-startX){
float k=((float)w)/contentW;
startX=(int) (startX*k);
endX=(int) (endX*k);
}
if(h>endY-startY){
float k=((float)h)/contentH;
startY=(int) (startY*k);
endY=(int) (endY*k);
}
w+=startX+startX;
h+=startY+endY;
textview.setPadding(startX, startY, endX, endY);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(w,h);
textview.setLayoutParams(lp);
}
});
You set good values for right and bottom borders. You just have to set same values for left and top borders, left border = right border and top border = bottom border.
The result in draw9patch:
And here the 9-patch file:
For your information, your image is not really suitable for using with 9-patch format.
I extended/adapted #ahtartam code. I am not sure if it is the cleanest way but it works for me. If someone needs help, just contact me or ask in comments!
public void setTextLayout(int orgW, int orgH,int actW,int actH,int top,int left) {
int startX = -1;
int endX = -1;
int startY = -1;
int endY = -1;
int contentW;
int contentH;
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.image);
int[] pixels = new int[orgW * orgH];
bmp.getPixels(pixels, 0, orgW, 0, 0, orgW, orgH);
for (int i = 0; i < orgW; i++) {
if (startX == -1 && pixels[orgW * (orgH - 1) + i] == Color.BLACK) {
startX = i;
}
if (startX != -1 && pixels[orgW * (orgH - 1) + i] != Color.BLACK) {
endX = i;
break;
}
}
for (int i = 0; i < orgH; i++) {
if (startY == -1 && pixels[orgW * (i + 1) - 1] == Color.BLACK) {
startY = i;
}
if (startY != -1 && pixels[orgW * (i + 1) - 1] != Color.BLACK) {
endY = i;
break;
}
}
m_marvin.setImageDrawable(new BitmapDrawable(getResources(), Bitmap.createBitmap(bmp, 1, 1, orgW - 2, orgH - 2)));
RelativeLayout.LayoutParams rp = (RelativeLayout.LayoutParams) m_marvin.getLayoutParams();
contentW=endX- startX;
contentH=endY-startY;
endX=orgW-endX;
endY=orgH-endY;
double scaleX = ((double)actW) / bmp.getWidth();
double scaleY = ((double)actH) / bmp.getHeight();
startX = (int) (startX * scaleX);
endX = (int) (endX * scaleX);
startY = (int) (startY * scaleY);
endY = (int) (endY * scaleY) ;
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams((int)(contentW*scaleX),(int)(contentH*scaleY));
layoutParams.setMargins(startX+rp.leftMargin+left, startY+rp.topMargin+top, endX+rp.rightMargin, endY+rp.bottomMargin);
layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL,RelativeLayout.TRUE);
m_text.setLayoutParams(layoutParams);
m_text.bringToFront();
}
Instead TextView I use SizeAwareImageView from -> https://stackoverflow.com/a/15538856/1438596
In my case it looks like this->
public class SizeAwareImageView extends ImageView {
MainActivity m_mainActivity;
public SizeAwareImageView(Context context,AttributeSet attrss){
super(context,attrss);
m_mainActivity = (MainActivity)context;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(m_mainActivity.getTextMeasured())return;
// Get image matrix values and place them in an array
float[] f = new float[9];
getImageMatrix().getValues(f);
// Extract the scale values using the constants (if aspect ratio maintained, scaleX == scaleY)
final float scaleX = f[Matrix.MSCALE_X];
final float scaleY = f[Matrix.MSCALE_Y];
// Get the drawable (could also get the bitmap behind the drawable and getWidth/getHeight)
final Drawable d = getDrawable();
final int origW = d.getIntrinsicWidth();
final int origH = d.getIntrinsicHeight();
// Calculate the actual dimensions
final int actW = Math.round(origW * scaleX);
final int actH = Math.round(origH * scaleY);
int top = (int) (imgViewH - actH)/2;
int left = (int) (imgViewW - actW)/2;
if(origW!=actW){
m_mainActivity.setTextMeasured(true);
m_mainActivity.setTextLayout(origW, origH, actW, actH,top,left);
}
}
}
You could use this tool for creating your nine-patch images.
Related
I'm using a library that extends the Gallery view.
However, I'm having a problem with the unselected items being pixelated. Digging into the code, I suspect that this is the function that does the image manipulations based on the input.
My question is that, is there a way to ensure that when the code calls postScale on the image matrix, my images wont get pixelated?
Hoping that someone can point me in the right direction.
The value of unselectedScale = 0.2f
#Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
// We can cast here because FancyCoverFlowAdapter only creates wrappers.
FancyCoverFlowItemWrapper item = (FancyCoverFlowItemWrapper) child;
// Since Jelly Bean childs won't get invalidated automatically, needs to be added for the smooth coverflow animation
if (android.os.Build.VERSION.SDK_INT >= 16) {
item.invalidate();
}
final int coverFlowWidth = this.getWidth();
final int coverFlowCenter = coverFlowWidth / 2;
final int childWidth = item.getWidth();
final int childHeight = item.getHeight();
final int childCenter = item.getLeft() + childWidth / 2;
// Use coverflow width when its defined as automatic.
final int actionDistance = (this.actionDistance == ACTION_DISTANCE_AUTO) ? (int) ((coverFlowWidth + childWidth) / 2.0f) : this.actionDistance;
// Calculate the abstract amount for all effects.
final float effectsAmount = Math.min(1.0f, Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - coverFlowCenter)));
// Clear previous transformations and set transformation type (matrix + alpha).
t.clear();
t.setTransformationType(Transformation.TYPE_BOTH);
// Alpha
if (this.unselectedAlpha != 1) {
final float alphaAmount = (this.unselectedAlpha - 1) * Math.abs(effectsAmount) + 1;
t.setAlpha(alphaAmount);
}
// Saturation
if (this.unselectedSaturation != 1) {
// Pass over saturation to the wrapper.
final float saturationAmount = (this.unselectedSaturation - 1) * Math.abs(effectsAmount) + 1;
item.setSaturation(saturationAmount);
}
final Matrix imageMatrix = t.getMatrix();
// Apply rotation.
if (this.maxRotation != 0) {
final int rotationAngle = (int) (-effectsAmount * this.maxRotation);
this.transformationCamera.save();
this.transformationCamera.rotateY(rotationAngle);
this.transformationCamera.getMatrix(imageMatrix);
this.transformationCamera.restore();
}
// Zoom.
if (this.unselectedScale != 1) {
final float zoomAmount = (this.unselectedScale - 1) * Math.abs(effectsAmount) + 1;
// Calculate the scale anchor (y anchor can be altered)
final float translateX = childWidth / 2.0f;
final float translateY = childHeight * this.scaleDownGravity;
imageMatrix.preTranslate(-translateX, -translateY);
imageMatrix.postScale(zoomAmount, zoomAmount);
imageMatrix.postTranslate(translateX, translateY);
}
return true;
}
I am trying to get the color from an image where the user touches the image. I am able to get the x,y coordinates and can calculate the pixels from it using Matrix, however my issue is it is not giving me the right color.
private void getColor(MotionEvent event, Button capture) {
float HeightRatio = (float) image.getHeight() / (float) imageView.getHeight();
float WidthRatio = (float) image.getWidth() / (float) imageView.getWidth();
Matrix inverse = new Matrix();
imageView.getImageMatrix().invert(inverse);
float[] touchPoint = new float[]{event.getX(), event.getY()};
i2.setX(event.getX());
i2.setY(event.getY());
inverse.mapPoints(touchPoint);
int x = Integer.valueOf((int) touchPoint[0]);
int y = Integer.valueOf((int) touchPoint[1]);
x = (int) (x * WidthRatio);
y = (int) (y * HeightRatio);
if (x < 0) {
x = 0;
} else if (x > image.getWidth() - 1) {
x = image.getWidth() - 1;
}
if (y < 0) {
y = 0;
} else if (y > image.getHeight() - 1) {
y = image.getHeight() - 1;
}
i2.setBackgroundColor(image.getPixel(x, y));
i2.setVisibility(View.VISIBLE);
capture.setBackgroundColor(image.getPixel(x, y));
}
This is the method i am using to get the color of the touched coordinate.
Thanks,
Vipin
try this:
final Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
imageView.setOnTouchListener(new OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event){
int x = (int)event.getX();
int y = (int)event.getY();
int pixel = bitmap.getPixel(x,y);
//then do what you want with the pixel data, e.g
int redValue = Color.red(pixel);
int blueValue = Color.blue(pixel);
int greenValue = Color.green(pixel);
return false;
}
});
Why so complicated?
https://stackoverflow.com/a/7807442/1979882
Have you tried this?:
private void getColor(MotionEvent event, Button capture) {
float[] touchPoint = new float[]{event.getX(), event.getY()};
float x = touchPoint[0];
float y = touchPoint[1];
ImageView imageView = ((ImageView)v);
Bitmap bitmap = ((BitmapDrawable)imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
capture.setBackgroundColor(image.getPixel(x, y));
}
I need to crop image like this
I need to draw partial image from center
I know there is draw() method of batch with a lot of params, but there is no good documentation about all this params, so i can't figure out how to use it.
Here is what i implemented:
public class TexturePart {
Texture tex;
Vector2 position;
// Target Dimension of image
int targetWidth;
int targetHeight;
// Src Dimensions of Image
int srcWidth;
int srcHeight;
int srcX;
int srcY;
// Ratio of dimension of target and source
float srcTargetRatioX;
float srcTargetRatioY;
// ImagePart variables with values between 0-100 to draw part of image
int startPercentX;
int endPercentX;
int startPercentY;
int endPercentY;
int clipWidth;
int clipHeight;
int clipSrcWidth;
int clipSrcHeight;
public TexturePart(TextureRegion reg, float x, float y) {
tex = reg.getTexture();
position = new Vector2(x, y);
srcX = reg.getRegionX();
srcY = reg.getRegionY();
srcWidth = reg.getRegionWidth();
srcHeight = reg.getRegionHeight();
clipSrcWidth = srcWidth;
clipSrcHeight = srcHeight;
startPercentX = 28;
startPercentY = 28;
endPercentX = 72;
endPercentY = 72;
SetTargetDimension(srcWidth, srcHeight);
}
public void setSrcWidthHeight(int width, int height){
this.srcWidth=width;
this.srcHeight=height;
}
public void setSrcHeight(int height){
this.srcHeight=height;
}
public void SetTargetDimension(int targetWidth, int targetHeight) {
this.targetWidth = targetWidth;
this.targetHeight = targetHeight;
clipWidth = targetWidth;
clipHeight = targetHeight;
srcTargetRatioX = (float) targetWidth / (float) srcWidth;
srcTargetRatioY = (float) targetHeight / (float) srcHeight;
}
public void SetStart(int x, int y) {
startPercentX = x;
startPercentY = y;
}
public void SetEnd(int x, int y) {
endPercentX = x;
endPercentY = y;
}
public void Draw(SpriteBatch sp) {
clipSrcWidth = (int) (Math.abs(startPercentX - endPercentX) / 100f * srcWidth);
clipSrcHeight = (int) (Math.abs(startPercentX - endPercentY) / 100f * srcHeight);
int startX = clipWidth/2 + (int) ((float) startPercentX / 100f * (float) srcX);
int startY = clipHeight/2 + (int) ((float) startPercentY / 100f * (float) srcY);
clipWidth = (int) (srcTargetRatioX * clipSrcWidth);
clipHeight = (int) (srcTargetRatioY * clipSrcHeight);
sp.begin();
float scaleX=targetWidth/(srcWidth+0.f);
float scaleY=targetHeight/(srcHeight+0.f);
sp.draw(tex, 0, 0, srcWidth, srcHeight, srcWidth, srcHeight, 1, 1, 0, startX, startY, clipSrcWidth, clipSrcHeight, false, false);
//sp.draw(tex, 0,0,clipWidth, clipHeight, clipWidth, clipHeight, clipSrcWidth, clipSrcHeight, false, false);
sp.end();
}
But its not working as expected
To crop the texture you just need to use TextureRegion
TextureRegion(Texture texture, int x, int y, int width, int height)
in your case it should look like:
Texture texture; //this is your original image
...
TextureRegion region = new TextureRegion(texture, texture.getWidth()*0.28f, 0, texture.getWidth()*0.44f, texture.getHeight() );
...
//now you can just draw your texture region
sp.draw(region); //you can also use other versions of draw to set region position on screen and so on
Why i set x as texture.getWidth()*0.28f? Because if want it centered it should have left margin = 50% of original texture width - texture region width.
(1 - 0.44) / 2 = 0.28
i am progrmatically creating radio button, and it works fine,
RadioImageButton RadioImageButton = new RadioImageButton(this);
RadioImageButton.setGravity(Gravity.CENTER);
RadioImageButton.setId(buttonId);
RadioImageButton.setTextColor(Color.BLACK);
RadioImageButton.setCompoundDrawablesWithIntrinsicBounds(icon, null,null, null)// use this to set the icon
RadioImageButton.setBackgroundDrawable(drawable);
RadioGroup.LayoutParams radioImageButtonParams = new RadioGroup.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT, 1f);
radioImageButtonParams.setMargins(0, 0, 1, 0);
RadioGroup.addView(RadioImageButton, radioImageButtonParams);
In RadioImageButton class
Drawable image;
public RadioImageButton(Context context) {
super(context);
setButtonDrawable(android.R.color.transparent);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (image != null) {
image.setState(getDrawableState());
final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
final int height = image.getIntrinsicHeight();
int y = 0;
switch (verticalGravity) {
case Gravity.BOTTOM:
y = getHeight() - height;
break;
case Gravity.CENTER_VERTICAL:
y = (getHeight() - height) / 2;
break;
}
int buttonWidth = image.getIntrinsicWidth();
int buttonLeft = (getWidth() - buttonWidth) / 3;
image.setBounds(buttonLeft, y, buttonLeft + buttonWidth, y + height);
image.draw(canvas);
}
}
But the icon which is being displayed is big , i need to decrease the size of that icon.
I have tried with setHeight but its not working.
RadioImageButton.setCompoundDrawablesWithIntrinsicBounds(icon, null,null, null)
this is used to set the icon
ok i fixed it by myself , here is the answer
private Drawable resize(Drawable image) {
Bitmap b = ((BitmapDrawable)image).getBitmap();
Bitmap bitmapResized = Bitmap.createScaledBitmap(b, 50, 50, true);// filter attribute set to true
return new BitmapDrawable(bitmapResized);
}
The code above is to modify the size of drawable, and make sure the filter attribute is set to true so that the icons does not look blur.
Hope it helps some one in future. Happy Coding :)
I want implement move a sprite from position (x ,y ) to position action_down (x1 , y1) .But I can't rotate it .Please help me .Thanks
This is my code:
public Sprite(GameView gameView, Bitmap bmp) {
this.gameView = gameView;
this.bmp = bmp;
this.width = bmp.getWidth() / BMP_COLUMNS;// create width, height
this.height = bmp.getHeight() / BMP_ROWS;
Random rnd = new Random(System.currentTimeMillis());
x = rnd.nextInt(gameView.getWidth() - bmp.getWidth());
y = rnd.nextInt(gameView.getHeight() - bmp.getHeight());
}
public void onDraw(Canvas canvas) {
Matrix matrix = new Matrix();
matrix.postTranslate(x, y);
float dx = x1-x;
float dy = y1-y;
float d = (float)Math.sqrt(dx*dx+dy*dy);
vx = (float) (dx*5/d)/3 ;
vy = (float) (dy*5/d)/3 ;
if(k==1){
x += vx ;
y += vy ;
}
currentFrame = ++currentFrame % BMP_COLUMNS;
int srcX = currentFrame * width;
int srcY = 0 * height;
Rect src = new Rect(srcX, srcY, srcX + width, srcY + height);
Rect dst = new Rect(x, y, x + width, y + height);
canvas.drawBitmap(bmp, src, dst, null);
}
You should look at matrix.postRotate or canvas.rotate.
Here you go:
Note: you need to convert from Bitmap to Image.
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
/**
* Created by Chris on 3/28/2014.
*/
public class Sprite {
private Image i;
public Sprite(Image image) {
this.i = image;
}
private BufferedImage image = null;
private Graphics2D graphics = null;
public void onDraw(Canvas canvas) {
if(image == null || graphics == null) {
setup();
}
Graphics g = canvas.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0, 0, image.getWidth(), image.getHeight());
//Where to draw the Sprite on the canvas.
int x = 100;
int y = 100;
//Because graphics is an instance of Graphics2D
//Converts the degrees "45" to radians.
double rotationAngle = Math.toRadians(45);
double locX = image.getWidth() / 2;
double locY = image.getHeight() / 2;
AffineTransform tx = AffineTransform.getRotateInstance(rotationAngle, locX, locY);
AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR);
graphics.drawImage(op.filter(image, null), 0, 0, null);
g.drawImage(image, x, y, (int) (image.getWidth() / 2), (int) (image.getHeight() / 2), null);
}
/**
* Sets the Image up.
*/
private void setup() {
if(image != null) {
image.flush();
image = null;
}
if(graphics != null) {
graphics.dispose();
graphics = null;
}
image = new BufferedImage(i.getWidth(null) * 2, i.getHeight(null) * 2, BufferedImage.TYPE_INT_ARGB);
graphics = image.createGraphics();
}
}