2015-09-18 29 views
0

我正在創建一個遊戲,其中會有很多可點擊的ImageView和一個不可點擊的imageView,當點擊可點擊的ImageView時,它應該將其切換位置與不可點擊的ImageView(在這個例子中,它叫做imageView2)。當imageview的寬度使用dp單位時,Android屬性動畫不起作用

當我爲我的imageView使用px單元時,一切正常。但是,正如您所知,使用px單位將導致不同設備上的顯示不同。但是,當我使用dp單位時,屬性動畫不起作用。我如何得到它與dp單位合作?

MainActivity.java

public class MainActivity extends Activity implements View.OnClickListener { 

    ImageView imageView1, imageView2; 
    float x, x_9, y, y_9; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     imageView1 = (ImageView) findViewById(R.id.imageView1); 
     imageView2 = (ImageView) findViewById(R.id.imageView2); 

     imageView1.setOnClickListener(this); 

    } 

    @Override 
    public void onClick(View v) { 

     // Get x position of clicked imageView 
     x = v.getX(); 
     // Get x position of imageView2 
     x_9 = imageView2.getX(); 

     // Get y position of clicked imageView 
     y = v.getY(); 
     // Get y position of imageView2 
     y_9 = imageView2.getY(); 


     // Check if imageViews are align with each other either horizontally or vertically 
     if((x == x_9 && y + 100 == y_9) || (x == x_9 && y - 100 == y_9) || (x + 100 == x_9 && y == y_9) || (x - 100 == x_9 && y == y_9)) { 

      // If they are aligned, swap their position with property animation 

      PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("translationX", x_9); 
      PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("translationY", y_9); 

      PropertyValuesHolder pvhX9 = PropertyValuesHolder.ofFloat("translationX", x); 
      PropertyValuesHolder pvhY9 = PropertyValuesHolder.ofFloat("translationY", y); 

      ObjectAnimator blockAnim = ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY); 
      blockAnim.setDuration(500); 
      blockAnim.setRepeatCount(0); 
      blockAnim.start(); 

      ObjectAnimator blockAnim2 = ObjectAnimator.ofPropertyValuesHolder(imageView2, pvhX9, pvhY9); 
      blockAnim2.setDuration(500); 
      blockAnim2.setRepeatCount(0); 
      blockAnim2.start(); 
     } 
    } 
} 

activity_main.xml中

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
xmlns:tools="http://schemas.android.com/tools"  android:layout_width="match_parent" 
android:layout_height="match_parent"  android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> 

    <RelativeLayout 
     android:id="@+id/relative" 
     android:background="@color/grey" 
     android:layout_width="400dp" 
     android:layout_height="400dp" 
     > 

     <ImageView 
      android:id="@+id/imageView1" 
      android:layout_width="100dp" 
      android:layout_height="100dp" 
      android:background="@drawable/smiley1"/> 

     <ImageView 
      android:id="@+id/imageView2" 
      android:layout_width="100dp" 
      android:layout_height="100dp" 
      android:background="@drawable/smiley2" 
      android:translationX="100dp"/> 

    </RelativeLayout> 

</RelativeLayout> 

如何解決這個問題?所有建議都非常受歡迎。謝謝。

至於建議由尼古拉·米盧蒂諾維奇,我加GlobalLayoutListener像下面

 this.findViewById(R.id.relative).getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
      @Override 
      public void onGlobalLayout() { 
       x = v.getX(); 
       x_9 = imageView2.getX(); 

       y = v.getY(); 
       y_9 = imageView2.getY(); 
      } 
     }); 
+0

嘗試使用http://developer.android.com/reference/android/view/ViewTreeObserver.OnGlobalLayoutListener.html 我相信這會使維度在該偵聽器中可見。 –

+1

謝謝你的回答,你能通過展示一個例子來幫助我,我如何在我的案例中實現這個OnGlobalLayoutListener? – Charas

回答

2

我認爲這樣做的方法是通過imageViews包含的實際值將硬編碼引用更改爲寬度和高度。在你的條件改變100 getHeight()或getWidth();

int height = imageView1.getHeight(); 
int width = imageView1.getWidth(); 

if((x == x_9 && y + height == y_9) || (x == x_9 && y - height == y_9) || 
    (x + width == x_9 && y == y_9) || (x - width == x_9 && y == y_9)){ 

} 

這樣你就沒有對px的引用。您使用的「100」值意味着100px。 hdpi設備的實際寬度或高度應該是1.5 * 100 = 150px。通過使用getWidth()和getHeight(),您可以在屏幕中使用px的實際值。我希望它很清楚。您將需要修改超過2個imageView的if條件,但原理相同。

最後,如果您希望動畫同步,最好使用AnimatorSet。

ArrayList <Animator> animations = new ArrayList<Animator>(); 
animations.add(ObjectAnimator.ofPropertyValuesHolder(v, pvhX, pvhY)); 
animations.add(ObjectAnimator.ofPropertyValuesHolder(imageView2, pvhX9, pvhY9)); 

AnimatorSet animatoreSet = new AnimatorSet(); 
animatorSet.setDuration(500); 
animatorSet.setRepeatCount(0); 
animatorSet.playTogether(animations); 
animatorSet.start(); 

通過這樣做,如果您需要添加監聽器,您只需添加一次。

+0

您不需要GlobalLayoutListener或PreDrawListener,因爲您已經知道每個imageView的位置和位置。這兩個監聽器用於在繪製之前知道視圖的確切位置,因爲您已經知道您不需要它們。 –

+1

你真了不起!這樣簡單的解非常感謝你的朋友,現在一切都完美了。但是,當我嘗試AnimatorSet時,出現錯誤,它在add方法中顯示此錯誤:無法解析方法'add(android.animation.ObjectAnimator)'。 – Charas

+0

對不起我的壞。看看編輯的答案。您需要讓動畫師集合一起播放動畫,並創建一個要播放動畫的數組列表。 –

0

下面這兩個方法查看文檔,找到哪一個最適合自己。 container將是你的根佈局(這RelativeLayout的頂部或該ID爲relative

container.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 
     @Override 
     public void onGlobalLayout() { 

     } 
    }); 

    container.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() { 
     @Override 
     public void onDraw() { 

     } 
    }); 

這是我實現這個監聽器的例子。 我在裏面做各種各樣的東西。請看一下。

public class CustomOnGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener { 

private Context context; 
private View fragment; 
private float x1; 
private float y1; 
private float x2; 
private float y2; 

public CustomOnGlobalLayoutListener(Context context, View view, float x1, float y1, float x2, float y2) { 
    this.context = context; 
    this.fragment = view; 
    this.x1 = x1; 
    this.y1 = y1; 
    this.x2 = x2; 
    this.y2 = y2; 
} 

@Override 
public void onGlobalLayout() { 
    fragment.setX(x1); 
    fragment.setY(y1); 
    removeOnGlobalLayoutListener(); 
    FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) fragment.getLayoutParams(); 
    fragment.setLayoutParams(layoutParams); 
    fragment.setPivotX(0); 
    fragment.setPivotY(0); 
    fragment.setScaleX((x2 - x1)/fragment.getMeasuredWidth()); 
    fragment.setScaleY((y2 - y1)/fragment.getMeasuredHeight()); 
    fragment.setAlpha(0f); 
    PropertyValuesHolder pA = PropertyValuesHolder.ofFloat(View.ALPHA, 1f); 
    PropertyValuesHolder pX = PropertyValuesHolder.ofFloat(View.X, 0f); 
    PropertyValuesHolder pY = PropertyValuesHolder.ofFloat(View.Y, 0f); 
    PropertyValuesHolder pSx = PropertyValuesHolder.ofFloat(View.SCALE_X, 1); 
    PropertyValuesHolder pSy = PropertyValuesHolder.ofFloat(View.SCALE_Y, 1); 
    final ObjectAnimator animator1 = ObjectAnimator.ofPropertyValuesHolder(fragment, pA, pX, pY, pSx, pSy); 

    animator1.setInterpolator(new AccelerateDecelerateInterpolator()); 
    animator1.setDuration(200); 
    animator1.start(); 

} 

private void removeOnGlobalLayoutListener() { 
    if (Build.VERSION.SDK_INT < 16) { 
     //noinspection deprecation 
     fragment.getViewTreeObserver().removeGlobalOnLayoutListener(this); 
    } else { 
     fragment.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
    } 
} 

}

不要忘記刪除GLOBAL LAYOUT偵聽器;

如果你有實現這個任何問題,寫出來,大家會想到什麼了:)

您還可以檢查在那裏我居然以此來實現從觸摸點與viewpager打開片段我的github回購。

https://github.com/mrnmilutinovic/HumanityTestProject

檢查ImagePagerFragment類,看看它的用法。 這段代碼是可編譯的,所以你也可以運行並看到它的工作原理。

+0

對不起,我不確定我是否真的瞭解它,所以我在onGlobalLayout()方法中添加了x = v.getX(),但它顯示了錯誤,我編輯了我的答案以添加onGlobalLayout( ),但我認爲我做錯了,請幫助我。謝謝。 – Charas

+0

我修改了答案。往上看。 –

+0

非常感謝你的幫助,我正在研究你的代碼和使用這種方法的例子,我想我可能需要它來做未來的項目。 – Charas

相關問題