简体   繁体   中英

Custom Android UI and multiple screen support

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!

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM