2016-04-11 10 views
0

Değerli dost StackOverflower,Android'de Matrix kullanılarak döndürülen ImageView'ın yarısı nasıl gösterilir?

bu örneği izleyin (code.tutsplus [dot] com/öğreticiler/android-sdk-yaratan-a-dönen-çevirici - mobil-8868), ben oluşturmak açabiliyorum Matrix kullanarak dönen bir ImageView. mantık aşağıdaki gibidir:

  • Yük ImageView
  • içine Bitmap dokunmatik etkinliğine yaptığı bir Matrix kullanılarak ImageView döndürün.

Bu, Bitmap tekerleği her döndürdüğünde çekilmeyeceği için performansı garanti eder. Ancak, tekerleğin sadece yarısını görüntülemek istiyorum ve image'un içeriği dinamik olduğundan, görüntüyü ikiye böldükten sonra yukarıdaki adımları izleyerek döndürmek mümkün olmayacaktır.

Ben ancak anladığım kadarıyla, doğrudan bu yüzden geri (korkunç bir performansa sahiptir) yeniden çizme Bitmap yöntemine düşmek, öldürürdüm o iş yapmak amacıyla kaynak Bitmap kırpma oluyor, ClipDrawable araştırılmıştır ettik.

ImageView görüntüsünü sınırlamanın bir yolu var, bu yüzden yalnızca bir kısmı görüntülenecek mi? Şimdiye kadar ne yaptık

:

MyRotateWheel sınıfı: düzen fi olarak

public class MyMatrixHelper { 
private Bitmap imageOriginal, imageScaled; 
private Matrix matrix; 
private int mImageHeight, mImageWidth; 

public MyMatrixHelper(Resources res, int id){ 
    // load the image only once 
    if (imageOriginal == null) { 
     imageOriginal = BitmapFactory.decodeResource(res, id); 
    } 

    // initialize the matrix only once 
    if (matrix == null) { 
     matrix = new Matrix(); 
    } else { 
     // not needed, you can also post the matrix immediately to restore the old state 
     matrix.reset(); 
    } 
} 

public boolean isNecessaryToScaleImage(int width, int height){ 
    if (mImageWidth == 0 || mImageHeight == 0) { 
     mImageWidth = width; 
     mImageHeight = height; 

     // resize 
     Matrix resize = new Matrix(); 
     resize.postScale((float) Math.min(mImageWidth, mImageHeight)/(float) imageOriginal.getWidth(), (float) Math.min(mImageWidth, mImageHeight)/(float) imageOriginal.getHeight()); 
     imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false); 

     // translate to the image view's center 
     float translateX = mImageWidth/2 - imageScaled.getWidth()/2; 
     float translateY = mImageHeight/2 - imageScaled.getHeight()/2; 
     matrix.postTranslate(translateX, translateY); 

     //imageOriginal.recycle(); 
     return true; 
    }else{ 
     return false; 
    } 
} 

public Bitmap getImageScaled() { 
    return imageScaled; 
} 

public Matrix getMatrix() { 
    return matrix; 
} 

:

public class MyRotateWheelView extends ImageView { 
private MyMatrixHelper mMatrixHelper; 
private int mWheelHeight, mWheelWidth; 

public MyRotateWheelView(Context context, AttributeSet attrs){ 
    super(context, attrs); 
    loadImage(R.drawable.my_rotate_wheel); 
    initWheel(); 
} 

public void loadImage(int id){ 
    mMatrixHelper = new MyMatrixHelper(getResources(), id); 
} 

public void initWheel(){ 
    setOnTouchListener(new MyOnTouchListener()); 
    //Since we only know after measuring the layout how much space our ImageView fills, we add an OnGlobalLayoutListener. 
    //In the onGlobalLayout method, we can intercept the event that the layout has been drawn and query the size of our view. 
    getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 

     @Override 
     public void onGlobalLayout() { 
      // method called more than once, but the values only need to be initialized one time 
      if (mMatrixHelper.isNecessaryToScaleImage(getWidth(), getHeight())) { 

       mWheelWidth = getWidth(); 
       mWheelHeight = getHeight(); 

       setImageBitmap(mMatrixHelper.getImageScaled()); 
       setImageMatrix(mMatrixHelper.getMatrix()); 
      } 
     } 
    }); 
} 

/** 
* Simple implementation of an {@link View.OnTouchListener} for registering the mWheel's touch events. 
*/ 
private class MyOnTouchListener implements View.OnTouchListener { 

    private double startAngle; 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 

     switch (event.getAction()) { 

      case MotionEvent.ACTION_DOWN: 
       startAngle = getAngle(event.getX(), event.getY()); 

       break; 

      case MotionEvent.ACTION_MOVE: 
       double currentAngle = getAngle(event.getX(), event.getY()); 
       double delta = startAngle - currentAngle; 

       rotateDialer((float) delta); //rotate 

       startAngle = currentAngle; 
       break; 

      case MotionEvent.ACTION_UP: 

       break; 
     } 
     return true; 
    } 
} 

/** 
* @return The angle of the unit circle with the image view's center 
*/ 
private double getAngle(double xTouch, double yTouch) { 
    double x = xTouch - (mWheelWidth/2d); 
    double y = mWheelHeight - yTouch - (mWheelHeight/2d); 

    switch (getQuadrant(x, y)) { 
     case 1: 
      return Math.asin(y/Math.hypot(x, y)) * 180/Math.PI; 
     case 2: 
      return 180 - Math.asin(y/Math.hypot(x, y)) * 180/Math.PI; 
     case 3: 
      return 180 + (-1 * Math.asin(y/Math.hypot(x, y)) * 180/Math.PI); 
     case 4: 
      return 360 + Math.asin(y/Math.hypot(x, y)) * 180/Math.PI; 
     default: 
      return 0; 
    } 
} 

/** 
* @return The selected quadrant. 
*/ 
private static int getQuadrant(double x, double y) { 
    if (x >= 0) { 
     return y >= 0 ? 1 : 4; 
    } else { 
     return y >= 0 ? 2 : 3; 
    } 
} 

/** 
* Rotate the mWheel. 
* 
* @param degrees The degrees, the mWheel should get rotated. 
*/ 
private void rotateDialer(int i, float degrees) { 
    mMatrixHelper.getMatrix().postRotate(degrees, mWheelWidth/2, mWheelHeight/2); 
    setImageMatrix(mMatrixHelper.getMatrix()); 
} 

}

MyMatrixHelper sınıf le:

<.MyRotateWheelView 
... 
android:scaleType="matrix"/> 

UPADTE 1:

Ben kısmen bu sorunu çözdük. Temas olayında güncellenmiş bir Matrix kullanarak görüntüyü ImageView içine çekmek için onDraw10 yöntemini geçersiz kıldım. Bu garanti performansı, görüntü yeniden çizilmediğinden ve görüntü ImageView'un içinde uygun kırpma ile dönüyor. Bununla birlikte, kalan sorun görüntü şu anda ImageView'un merkezi etrafında döndürülüyor olmasıdır. Bu çözümün çalışması için, görüntünün merkezinin koordinasyonunu elde etmenin bir yolunu bulmaya ihtiyacım var. Herhangi bir öneri?

Kod pasajı:

private class MyOnTouchListener implements View.OnTouchListener { 

    private double startAngle; 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 

     switch (event.getAction()) { 

      ... 

      case MotionEvent.ACTION_MOVE: 
       double currentAngle = getAngle(event.getX(), event.getY()); 
       double delta = startAngle - currentAngle; 

       updateMatrix((float)delta); 
       invalidate(); 

       startAngle = currentAngle; 
       break; 

      ... 
     } 
     return true; 
    } 
} 

private void updateMatrix(float delta){ 
    matrix.postRotate(delta, getWidth()/2, getHeight()/2); //need to find out the coordination of the center of the image 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    canvas.drawBitmap(originalImage, matrix, paint); 
} 

GÜNCELLEME 2:

Ben resmin merkezinin koordinatı nasıl hesaplanacağını anladım.Şu anda görüntünün ekrandan daha büyük olduğu varsayımını yapıyorum, bu yüzden her vaka düzgün bir şekilde ele alındığında tam çözüm gönderilecektir.

Maalesef başka bir sorunla karşılaşıyorum.

Picture

Ancak resim çizilir: my çözüm çalışmalarını yapmak amacıyla, görüntünün alt Resim A bunun olduğu gibi merkezli ImageView ve düzgün alt ile uyumlu olmalıdır Resim B'daki gibi ImageView içine.

Herhangi birinin, görüntünün altını görünümün tabanıyla doğru şekilde ortalayıp hizalamanın yolunu gösterebilirse çok minnettar olurum.

cevap

0

Sevgili sevgili StackOverflower,

benim sorunu hallettim. Aslında çok basit. Aslında Matrix'un ekran koordinasyonunu takip ettiğini farz etmeliyim, aslında aslında View koordinasyonunu takip ediyor.

Picture

Sonra çözüm çok basit::

getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { 

     @Override 
     public void onGlobalLayout() { 
      // method called more than once, but the values only need to be initialized one time 
      if (mWheelHeight == 0 || mWheelWidth == 0) { 
       mWheelHeight = getHeight(); 
       mWheelWidth = getWidth(); 

       // resize 
       Matrix resize = new Matrix(); 
       resize.postScale((float)Math.min(mWheelWidth, mWheelHeight)/(float)imageOriginal.getWidth(), (float)Math.min(mWheelWidth, mWheelHeight)/(float)imageOriginal.getHeight()); 
       imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false); 
       setImageBitmap(imageScaled); 

       // center the image on x axis and move it upward on y axis 
       float translateX = mWheelWidth/2 - imageScaled.getWidth()/2;      
       float translateY = -imageScaled.getHeight()/2; //modify this to your liking, I only want to show the bottom half of the image. 
       matrix.postTranslate(translateX, translateY); 
       setImageMatrix(matrix); 
      } 
     } 
    }); 

dokunma olayı hala aynı:

private class MyOnTouchListener implements View.OnTouchListener { 

    private double startAngle; 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 

     switch (event.getAction()) { 

     ... 

      case MotionEvent.ACTION_MOVE: 
       double currentAngle = getAngle(event.getX(), event.getY()); 
       double delta = startAngle - currentAngle; 

       updateMatrix((float)delta); 
       invalidate(); 

       startAngle = currentAngle; 
       break; 

     ... 
     } 
     return true; 
    } 
} 

bir pivot koordinat güncellemek aşağıdaki resme bakınız :

private void updateMatrix(float delta){ 
    matrix.postRotate(delta, getWidth()/2, 0f); 
} 

@Override 
protected void onDraw(Canvas canvas) { 
    canvas.drawBitmap(imageScaled, matrix, paint); 
} 

Hepinize hasta için teşekkür ederiz.

İyileştirme:

Benim ilk çözüm çalışma cezası ve tüm sadece dönen tekerleğin senin düzen yarısını görüntülemek istiyorum. Ancak, olumsuz diğer Views diğer ImageView bloğu üzerinde kullanılmayan alan ve karmaşık bir düzeniniz varsa, bu altında diğer View dokunma olayı alamıyor. Bu geliştirilmiş çözümle, ImageView boyutlarını sınırlayabilirsiniz, böylece aşağıdaki Resimde olduğu gibi diğer View kodlarını engellemezsiniz. senin Layout.xml onGlobalLayout() yöntemde

<.MyWheelView 
    android:id="@+id/some_id" 
    android:layout_width="match_parent" 
    android:layout_height="100dp" //change to suit your need 
    android:layout_centerInParent="true" 
    android:src="@drawable/protractor_wheel" 
    /> 

yılında

Picture

, şöyle değiştirin:

@Override 
     public void onGlobalLayout() { 
      // method called more than once, but the values only need to be initialized one time 
      if (mWheelHeight == 0 || mWheelWidth == 0) { 
       mWheelHeight = getHeight(); 
       mWheelWidth = getWidth(); 

       // resize 
       Matrix resize = new Matrix(); 
       resize.postScale((float)Math.max(mWheelWidth, mWheelHeight)/(float)imageOriginal.getWidth(), (float)Math.max(mWheelWidth, mWheelHeight)/(float)imageOriginal.getHeight()); 
       imageScaled = Bitmap.createBitmap(imageOriginal, 0, 0, imageOriginal.getWidth(), imageOriginal.getHeight(), resize, false); 
       setImageBitmap(imageScaled); 

       // center the image on x axis and move it upward on y axis 
       float translateX = mWheelWidth/2 - imageScaled.getWidth()/2; 
       float translateY = - 0.75f * imageScaled.getHeight(); //edit show how much of the image will get displayed (in my case I move 75% of my image upward) 
       matrix.postTranslate(translateX, translateY); 
       setImageMatrix(matrix); 

       //calculate pivotY only once 
       pivotY = 0.25f * imageScaled.getHeight() - (float)imageScaled.getHeight()/2; 
      } 
     } 
    }); 

Sonra updateMatrix biz bunu:

private void updateMatrix(float delta){ 
    matrix.postRotate(delta, getWidth()/2, pivotY); 
} 

Umarım ki çözümüm size yardımcı olabilir, hasta için teşekkürler.

İlgili konular