I am trying to create a tab-like interface where I will switch views by sliding left/right. I display to the user what page they are on by adding a blue glow to the back of the tab icon shown here:
I did this by creating a custom view that will draw the background glow (if the tab is selected) and then the icon. My issue is that the glow is too large. All I need to do is to make it smaller so the sides don't get clipped like they are now (the glow overlaps the page on the bottom by design).
The glow was created using a shape drawable in XML (just a simple radial gradient).
I have tried changing the size of the shape in XML but it always comes out the same. I tried adjusting attributes under and tried adjusting the height and width under too.
Constructor:
public TabIconView(Context context, Bitmap tab)
{
super(context);
back = BitmapFactory.decodeResource(getResources(), R.drawable.background_blue_glow);
this.tab = tab;
}
onMeasure and onDraw:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
setMeasuredDimension(tab.getWidth() * 2, tab.getHeight() * 2);
}
#Override
protected void onDraw(Canvas canvas)
{
width = getMeasuredWidth();
height = getMeasuredHeight();
if (selected)
canvas.drawBitmap(back, (width - back.getWidth()) / 2, (height - back.getHeight()) / 2, null);
canvas.drawBitmap(tab, (width - tab.getWidth()) / 2, (height - tab.getHeight()) / 2, null);
super.onDraw(canvas);
}
Any ideas will be greatly appreciated.
One of the versions of Canvas.drawBitmap() lets you specified the width and height that you want the bitmap to have when drawn on screen. You could also simply rescale the bitmap when you load it (the Bitmap class has methods to create scaled versions of bitmaps.)
Figured it out. In case anybody wants to know...
public TabIconView(Context context, Bitmap tab)
{
super(context);
int backSize = (int) (42 * context.getResources().getDisplayMetrics().density + .5f);
b = BitmapFactory.decodeResource(getResources(), R.drawable.background_blue_glow);
back = Bitmap.createScaledBitmap(b, backSize, backSize, false);
this.tab = tab;
}
I had to create a scaled bitmap from the bitmap that was generated from the shapedrawable.
Related
As you can see in image, we have two type of ImageView, one type Horizontal and another Vertical. We want to load image to them in the way that bitmap fill the ImageView, images can be smaller ( like image #1 ) or bigger and taller ( like image #2 ).
Our goal is something like shown in image, we want to scale images on their X-Axis and crop overfllow of drawable in Y-Axis
We tried almost all scale-type, but results does not satisfy us, unfortunately
If you want to make width of drawable match with ImageView's width you can use Matrix:
public Matrix scaleWidthMatrix(int imageWidth, int viewWidth) {
Matrix scaleMatrix = new Matrix();
float scale = (float) viewWidth / imageWidth;
scaleMatrix.setScale(scale, scale);
return scaleMatrix;
}
This method returns a scale Matrix to scale image so that its width matches with ImageView and it does not consider height factor, Therefore parts of scaled drawable that is out of ImageView's boundary (in this case lower part of drawable) will be cropped.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView iv = (ImageView) findViewById(R.id.iv);
iv.getViewTreeObserver().addOnPreDrawListener(
new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
int imageWidth = iv.getDrawable().getIntrinsicWidth();
Matrix matrix = scaleWidthMatrix(imageWidth, iv.getWidth());
//we should setScaleType to Matrix in order to use image matrix
iv.setScaleType(ImageView.ScaleType.MATRIX);
iv.setImageMatrix(matrix);
//No need to call again so remove it
iv.getViewTreeObserver().removeOnPreDrawListener(this);
return true;
}
});
PS:
OnPreDrawListener gets called just before onDraw method gets invoked. At this point, all views in the tree have been measured so you can pass valid arguments to scaleWidthMatrix method.
Before all, I apologies for my English.
I'm a newbie in programming of Android App and I recently discovered the Canvas and Bitmap, so I decided to make a "Game" that can only use landscape. I discovered too the SurfaceView and how implement a background on my SurfaceView, but the first of all is that my background is an image 496x288.
I was searching in internet to learn how I can scaled well to fill all the screen of my phone with the background, and another screens. So I find this code and try to use in my app.
#SuppressLint("WrongCall")
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
Bitmap background = BitmapFactory.decodeResource(getResources(), R.drawable.fondo1escalado);
float scale = (float) background.getHeight() / (float) getHeight();
int newWidth = Math.round((background.getWidth() / scale));
int newHeight = Math.round(background.getHeight() / scale);
scaled = Bitmap.createScaledBitmap(background, newWidth, newHeight, true);
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#SuppressLint("WrongCall")
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLUE);
canvas.drawBitmap(scaled, 0,0, null);
}
It works, but it doesn't work well. I got this:
(Don't worry about the character)
It scales well but don't fit all the screen (See the blue background).
So, like a good programmer I try to fix this using a GUI that I have designed wich dimensions are 296x912, I used the same code, and it scalates well in the Height but not in the Width for all the screens even a tablet.
This is the code of the GUI
float scalaInterfazAltura = (float) interfaz.getHeight() / (float) getHeight();
int newHeightInterfaz = Math.round(interfaz.getHeight() / scalaInterfazAltura);
int newWidthInterfaz = Math.round(interfaz.getWidth() / scalaInterfazAltura);
scaledinterfaz = Bitmap.createScaledBitmap(interfaz, newWidthInterfaz, newHeightInterfaz, true);
canvas.drawBitmap(scaledinterfaz, getWidth() - interfaz.getWidth()/2, 0, null);
So, my question is: There is a thing to scale well in Surfaceview? I'm doing something wrong?
Thank you.
It happens cause Your display height more than View height.
Try to use surfaceView.getHeight() instead of interfaz.getHeight().
Also You can use
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
in Your Activity before setContentView() to make Your game fullscreen.
I have two images that don't always completely fit onto the screen. Therefore I want to crop them (like CENTER_CROP does) but in a way, so that the bottom area of the image is always visible. Both images fill the entire screen width and each 1/2 of the screen height.
I found a similar solution here:
ImageView scaling TOP_CROP
The accepted solution works perfectly, but I can't figure out how to change the matrix to make it BOTTOM_CROP instead.
Working Code for TOP_CROP:
setScaleType(ScaleType.MATRIX);
Matrix matrix = getImageMatrix();
float scaleFactor = (getWidth() - Data.getImgPadding(c)) / (float) getDrawable().getIntrinsicWidth();
matrix.setScale(scaleFactor, scaleFactor, 0, 0);
setImageMatrix(matrix);
Note: A padding to the right is set programmatically, therefore it needs to be included in the calculation (the value is read by Data.getImgPadding(c)).
For BOTTOM_CROP I thought I'd use:
matrix.setScale(scaleFactor, scaleFactor, 0, getHeight());
But it's not really working, for the first image the bottom part is displayed more or less correctly, but there is some sort of margin below it - the bottom image border should be exactly at the bottom ImageView border. I assume I have to use the padding somehow but I don't know how to caculate the "new" image height after the horizontal padding value is set.
The bigger problem however is that (for whatever reason) when I set the value py in setScale() the second ImageView is suddenly empty... both views use the same layout xml, but that can't be the reason as the original code works perfectly on both.
I know this is a long time gone, but I've modified the answer in the post to suit your need.
#Override
protected boolean setFrame(int l, int t, int r, int b) {
boolean hasChanged = super.setFrame(l, t, r, b);
Matrix matrix = getImageMatrix();
float scaleFactor = getWidth() / (float) getDrawable().getIntrinsicWidth();
matrix.setScale(scaleFactor, scaleFactor, 0, 0);
// The Important Bit
Drawable drawable = getDrawable();
float heightD = drawable.getIntrinsicHeight();
float height = getHeight();
matrix.setTranslate(0, height - heightD);
setImageMatrix(matrix);
return hasChanged;
}
Hope it helps!
I newbie to android and graphic development.
I implement a custom-view and want to draw to canvas.
I set the customview size to be (width x (width/2)) so the rectangle height is half of the width.
Now when start drawing, its easy for me to draw on a square area like 1X1.
like this:
protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int ChosenSize = Math.min(widthSize, heightSize);
int width = ChosenSize;
int height = (int)(ChosenSize/2);
setMeasuredDimension(width,height);
}
#Override protected void onDraw(Canvas canvas){
float width = (float)getWidth();
float height = (float)getHeight();
canvas.save(Canvas.MATRIX_SAVE_FLAG);
canvas.scale(width ,height );
// start drawing in a 1X1 square coordinates
canvas.restore();
}
But after restore() the result is stretched a little bit.
What am i doing wrong ??
Note: I have notice that when not using scale and working with the rectangle width and height the
result looks Ok
Thx
I figure it out.
The reason my drawing stretch, is because I scale from rectangle to square which is mistake.
Usually when canvas is square it easy to draw on 1x1 square, so I scale to canvas.scale(width,height),
But when canvas is rectangle like (width,width/2), I should scale to (width,height/width) to get rect of 1x2.
so after I change scaling to canvas.scale(width,height/width)
I have created this class which extends View and draws a graph in Canvas. While drawing a graph I am considering actual screen height and width and it draws a graph according to that.
My problem is I am using this View as a widget in another activity with a desired size say 100 by 150..but the View class doesn't scale itself and only shows a clipped part of it not the graph. I know O have to do some calculation to fit this canvas into desired size but I have no clue how to do that..Any help would be great!!
Code where I am drawing graph is
public class GraphPlotting extends View
{
public void onDraw(Canvas canvas)
{
readPoints();
Paint paint1 = new Paint();
paint1.setColor(Color.rgb(0xFF,0xFF, 0xFF));
paint1.setStrokeWidth(1.0f);
Paint paint2 = new Paint();
paint2.setColor(Color.rgb(0xFF,0xFF, 0xFF));
paint2.setStrokeWidth(10.0f);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
canvas.drawPaint(paint);
canvas.drawLines(p,paint1);
}
public void readPoints()
{
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
height = dm.heightPixels;
width = dm.widthPixels;
// drawing graph based on above dimension which in my case is 480 by 800
}
xml Layout where I am using this View
<RelativeLayout
android:layout_width="200dp"
android:layout_height="200dp"
android:orientation="vertical"
android:layout_below="#+id/btn_analyze"
android:layout_centerHorizontal="true"
android:id="#+id/rlgraph"
>
<com.aventusoft.mylynel.GraphPlotting
android:id="#+id/view1"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</RelativeLayout>
I want to fit my canvas with my Relative layout height and width and graph should visible in that area..currently its showing the View but only part of it..Graph is not visible at all..Please help me in calculation I need to do..
Copy/paste direct from one of my own classes which extends ImageView to draw a graph. The idea is that you can put this into any layout. The class takes care of it's own measurements.
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
widgetHeight = h;
widgetWidth = w;
if (sizeChangedObservers != null && sizeChangedObservers.size() > 0) {
for (SizeChangedObserver observer : sizeChangedObservers) {
observer.callback(w, h);
}
}
updateIncrements();
}
The sizeChangedObservers just let's me notify other classes if the graph size changes, e.g. I have scale indicators on the X and Y axis. updateIncrements() is where I figure out how many pixels each X and Y represents using the device screen resolution, graph size and DPI count.
Using this approach, the canvas will be whatever size it is and you don't care. When you plot, you just use x * xPixels and y * yPixels which are the calculated pixels per value.
[EDIT] Try reading this first http://developer.android.com/training/custom-views/custom-drawing.html