0

My application has a button as well as an ImageView (of a piano keyboard) arranged in a FrameView. When a key on the piano keyboard is clicked, the button gets moved there by setting it's topMargin and leftMargin via the following:

FrameLayout.LayoutParams params = (FrameLayout.LayoutParams)noteButton.getLayoutParams();
params.setMargins(leftMargin,topMargin,0,0);

The actual margin is calculated differently depending on the key, but generally uses the Width and Height aquired via getHeight() and getWidth() within onWindowFocusChanged(). The calculation for the first black key, C# or Db, looks like the following:

leftMargin = (int) (pianoImageViewWidth/7 - buttonSize/2);

Since the piano graphic is 7 keys wide and the black key is between the first and second key (see image).

My problem now is the actual margins are not centered; they're actually somewhat far off, like in the following example.

Example

It is generally worse towards the left side of the keyboard. On smaller dp devices, it's so far to the left it's out of the bounds of the black key. I absolutely cannot figure out what is going wrong there, I hope somebody here can help me adjust this.

Additionally, here is the code to get the width and height:

    int pianoImageWidth  = imagePiano.getWidth();
    int pianoImageHeight = imagePiano.getHeight();
    int buttonSize = noteButton.getWidth();

And the XML of the actual piano and button:

<FrameLayout
    android:id="@+id/piano_frame"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textView">

    <Button
        android:id="@+id/note_button"

        android:visibility="invisible"
        android:text="C"
        android:textColor="#FFFFFF"
        android:textSize="20sp"
        android:textAlignment="center"
        android:padding="0dp"

        android:layout_width="32dp"
        android:layout_height="32dp"
        android:background="@drawable/note"
        android:shadowColor="#A8A8A8"
        android:shadowDx="0"
        android:shadowDy="0"
        android:shadowRadius="5"
        android:layout_margin="0dp"
        />

    <ImageView
        android:id="@+id/piano_image"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:cropToPadding="false"
        app:srcCompat="@drawable/piano" />
</FrameLayout>
  • margins you're setting in `px` or recalculating it into `dp` values? – Dumbo Apr 12 '18 at 11:23
  • @Dumbo I'm not doing any conversions. I should be getting it in px with getWidth() and setting it in px with params.setMargins() –  Apr 12 '18 at 11:27
  • The different devices have different amount of pixels so you should use `dp` because it is more adaptive. See: https://stackoverflow.com/a/2025541/5272951 – Dumbo Apr 12 '18 at 11:37
  • @Dumbo I am calculating this during runtime with the actual amount of pixels on the screen. You can't set margins in dp during runtime. –  Apr 12 '18 at 11:39
  • You can do it. If I not mistaken you should use: `getResources().getDisplayMetrics().density;` to get density. And multiply the value with the `leftMargin` and `topMargin` before setting them as margin values. – Dumbo Apr 12 '18 at 11:41
  • @Dumbo I tried doing this, but the Margin becomes way bigger. I think the conversion into dp is really not needed here, since I've only done calculations with the picture size on the screen in pixels and ratios thereof. –  Apr 12 '18 at 11:51
  • Maybe, I don't know why it could be wrong. Because whenever I creating any `View` programmatically I am always converting `px` into `dp` and thats works fine for me all the time and the created View is the same in all different devices – Dumbo Apr 12 '18 at 11:58
  • @Dumbo But if you check the Documentation at https://developer.android.com/reference/android/view/View.html#getWidth() , you can see that getWidth() returns the width in pixels, not dp. And params.setMargins() also takes the margins in px, not dp. –  Apr 12 '18 at 12:02
  • As I said I am offering you to get `px` from `getWidth()`, convert it to `dp` value and set it to `setMargin()`. And what the android developer page says is not always the best practice – Dumbo Apr 12 '18 at 12:07
  • @Dumbo Ah, I got you now. Sadly using that approach, the margins end up way too big again, since the LayoutParams.setMargins() takes pixel value margins, not dpi. –  Apr 12 '18 at 12:12
  • Try to use these methods for converting `px` to `dp`: https://stackoverflow.com/a/9563438/5272951 – Dumbo Apr 12 '18 at 12:15
  • @Dumbo This, too, does not work. Can you tell me why I want to convert into dpi if I get the image size in Pixels and the Margins programmatically gets set in Pixels? –  Apr 12 '18 at 12:20

1 Answers1

0

getHeight() and getWidth() is going wrong in your case i think. Can you please show more code of how you are taking getHeight() and getWidth() ?

the correct way to get width and height is :

view.getLayoutParams().height
view.getLayoutParams().width
Hitesh Sarsava
  • 666
  • 4
  • 15
  • I am doing the following `int pianoImageWidth = imagePiano.getWidth(); int pianoImageHeight = imagePiano.getHeight();` Using getLayoutParams().height only gives me the constant for "Wrap Content", since this is what I used. It doesn't return actual sizes. –  Apr 12 '18 at 11:51
  • so for your piano image you should to set match parent . Can you please provide the xml design? – Hitesh Sarsava Apr 12 '18 at 12:02
  • The correct way to get width and height is `getHeight()` and `getWidth()`, because this is the value of pixels of (top minus bottom) and (right minus left). `top`, `bottom`, `right` and `left` is the distance from edge to the `View`. – Dumbo Apr 12 '18 at 12:04
  • I added the XML as well as the calls to retrieve the image size to the Post. –  Apr 12 '18 at 12:08
  • May be you are missing the spacing around the white keys in pianoImageViewWidth/7 – Hitesh Sarsava Apr 12 '18 at 12:31