0

I know these kinds of questions have been asked before, but I haven't seen one of this type yet. I am creating a custom android UI using android canvas. I have created all the necessary drawables for it and put them in the appropriate folders and I am now drawing the UI with this code:

public class MainMenuView extends View {

private Bitmap pasteImage;
private Bitmap adventureLetters;
private Bitmap settingsLetters;
private Bitmap quitLetters;
private Bitmap backgroundImage;
private DisplayMetrics metrics;

public MainMenuView(Context context){
    super(context);
    pasteImage = decodeFile(R.drawable.paste, 200, true);
    Log.w("Visina imagea", String.valueOf(pasteImage.getHeight()));
    pasteImage.recycle();
}

public MainMenuView(Context context, AttributeSet attrSet){
    super(context, attrSet);
    metrics = context.getResources().getDisplayMetrics();
    pasteImage = decodeFile(R.drawable.paste, 330, true);
    adventureLetters = decodeFile(R.drawable.adventureletters, 100, true);
    settingsLetters = decodeFile(R.drawable.settingsletters, 100, true);
    quitLetters = decodeFile(R.drawable.quitletters, 50, true);
    Log.w("Je li image null? ", pasteImage == null ? "da" : "ne");
    backgroundImage = decodeFileScaled(R.drawable.toothpastebackground);
    backgroundImage = Bitmap.createScaledBitmap(backgroundImage, metrics.widthPixels - 20, metrics.heightPixels, true);
    //adventureLetters = BitmapFactory.decodeResource(getResources(), R.drawable.adventureletters);
    //settingsLetters = BitmapFactory.decodeResource(getResources(), R.drawable.settingsletters);
    //quitLetters = BitmapFactory.decodeResource(getResources(), R.drawable.quitletters);
}

@Override
protected void onMeasure(int widthMeasure, int heightMeasure){
    setMeasuredDimension(calculateMeasure(widthMeasure), calculateMeasure(heightMeasure));
    Log.w(String.valueOf(calculateMeasure(widthMeasure)), "Izmjereno");
}

private static final int DEFAULT_SIZE = 70;
private int calculateMeasure(int measure) {

    int result = (int)(DEFAULT_SIZE * getResources().getDisplayMetrics().density);
    int specMode = MeasureSpec.getMode(measure);
    int specSize = MeasureSpec.getSize(measure);

    if(specMode == MeasureSpec.EXACTLY) result = specSize;
    else if(specMode == MeasureSpec.AT_MOST){
        result = Math.min(result, specSize);
    }

    return result;
}

@Override
protected void onDraw(Canvas canvas){
    super.onDraw(canvas);
    if(canvas == null) Log.w("Canvas je null", "Da");
    else Log.w("Canvas nije null", "ne");
    Log.w("Usao u onDraw", "u onDraw sam sad");
    canvas.save();
    if(pasteImage == null) Log.w("Slika je null", "null slika");
    canvas.drawBitmap(backgroundImage, 0, 0, null);
    Log.w("Dimenzije slike sirina x visina bg", backgroundImage.getWidth() + " " + backgroundImage.getHeight());
    canvas.drawBitmap(pasteImage, 110, 420, null);
    canvas.drawBitmap(adventureLetters, 50,  60, null);
    canvas.drawBitmap(settingsLetters, 80,  60, null);
    canvas.drawBitmap(quitLetters, 100,  60, null);
    pasteImage.recycle();
    adventureLetters.recycle();
    settingsLetters.recycle();
    quitLetters.recycle();
    canvas.restore();
}

private Bitmap decodeFile(int id, int size, boolean resize){

        //Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), id, o);

        //The new size we want to scale to
        final int REQUIRED_SIZE = size;

        //Find the correct scale value. It should be the power of 2.
        int scale = 1;
        while(o.outWidth/scale/2 >= REQUIRED_SIZE && o.outHeight/scale/2 >= REQUIRED_SIZE)
            scale*=2;

        //Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        return BitmapFactory.decodeResource(getResources(), id, o2);

}

private Bitmap decodeFileScaled(int id){

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeResource(getResources(), id, options);
    Log.w("Sirina x visina displaya", metrics.widthPixels + "x" +   metrics.heightPixels);
    options.inSampleSize = calculateScale(options, metrics.widthPixels, metrics.heightPixels);

    options.inJustDecodeBounds = false;
    return BitmapFactory.decodeResource(getResources(), id, options);
}

private int calculateScale(BitmapFactory.Options options, int reqWidth, int reqHeight){

    final int rawHeight = options.outHeight;
    final int rawWidth = options.outWidth;
    int inSampleSize = 1;

    if (rawHeight > reqHeight || rawWidth > reqWidth) {

        // Calculate ratios of height and width to requested height and width
        final int heightRatio = Math.round((float) rawHeight / (float) reqHeight);
        final int widthRatio = Math.round((float) rawWidth / (float) reqWidth);

        // Choose the smallest ratio as inSampleSize value, this will guarantee
        // a final image with both dimensions larger than or equal to the
        // requested height and width.
        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}
}

You can see immediately that I'm using some hardcoded values for positioning on screen. Can you give me some advice on how to code it so that it appears as it should on every screen(especially medium and high dimensions). As it should means no blurring tearing empty space and so on. If you need any more info let me know in the comments and thank you very much!

EldarGranulo
  • 1,575
  • 1
  • 14
  • 37

1 Answers1

0

You should always use positions relatives to the screen. For example:

float left = getScreenSize().x * 0.10f;
float top = getScreenSize().y * 0.10f;

canvas.drawBitmap(pasteImage, left, top, null);

private float getScreenSize() {
     WindowManager windowManager = (WindowManager) getContext.getSystemService(Context.WINDOW_SERVICE);
     Display display = windowManager.getDefaultDisplay();
     Display display = getWindowManager().getDefaultDisplay();
     Point size = new Point();
     display.getSize(size);
     return size;
}

But If you are going to use absolute values, you should do it in dp, not px.

Resources resources = getResources();

float left = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 140, resources.getDisplayMetrics());

float top = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 140, resources.getDisplayMetrics());

canvas.drawBitmap(pasteImage, left, top, null);
Víctor Albertos
  • 8,093
  • 5
  • 43
  • 71
  • Is there any way I may avoid creating these magic numbers(width * something) and so on? – EldarGranulo Aug 30 '14 at 13:37
  • Magic? :) If you were using views instead of drawing the `Drawable` as `Bitmap`, you could use `LayoutParams` to set the views positions relatives to themselves. [Here](http://stackoverflow.com/questions/4638832/how-to-programmatically-set-the-layout-align-parent-right-attribute-of-a-button) – Víctor Albertos Aug 30 '14 at 13:46
  • http://stackoverflow.com/questions/25507968/android-user-interface-using-photoshop-design This is what I'm trying to create. Is it possible using layout params? – EldarGranulo Aug 30 '14 at 13:54
  • 1
    Like @S.D. said to you, this design is extremely difficult to achieve. I’m sorry but I think you won’t be able to fit the views with such detail level.If I were you, I would try to redesign the UI taking care of the caveats about resolutions and proportions. – Víctor Albertos Aug 30 '14 at 14:12
  • Thank you for you help, I may be able to do it like this with a canvas and manually drawing everything and using screen size to handle positioning on multiple screens. – EldarGranulo Aug 30 '14 at 14:19
  • You're welcome @Matsura! I hope you get lucky, really. – Víctor Albertos Aug 30 '14 at 14:21