51dev.com IT技术开发者社区

51dev.com 技术开发者社区

一个很小短但是可以旋转的图片效果

Android互联网报道阅读(12)2019-09-18 收藏0次评论

今天要写的内容呢,是一个圆形旋转的效果(渣渣表示写一个效果用了丧心病狂的半天时间),国际惯例效果图先行,请看图

本来我之前是做成的点击图片然后获取rgb,但是产品要求要能滑动,好吧做为一个有节操的程序猿,勉为其难写一个效果吧(其实我内心是拒绝的)。具体效果要求是圆环可以旋转,当手指离开的时候要获取指针棒指向图片的位置的rgb值(圆环是图片给的一张整图)。所以呢要解决的问题就2个:

指针的位置坐标相对于圆盘图片所在的坐标值;根据坐标值获取图片的rgb值

让圆环转动

先看最主要的问题怎么让圆盘转动呢,你可以用canvas.rotate(angle, mCenterX, mCenterY)实现转动,要怎么跟随手指转动呢,这个要借用一下高中的数学姿势,由于我高中数学是体育老师教的下面方法我说得不好,不要打我。

先画一个草图讲解一下
vc7Sw8fPyMvjZG93bs/CyrG68rXEvce2yNa1o6zIu7rzbW92ZcqxuvK1xL3HtsjWtc/gvPW1w7W9vce2yLLu1rWjrNPDvce2yLLu1rXIpdD916q7rbK8oaO/tM/C1PXDtLzGy+O9x7bI1rXE2DwvY29kZT48L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;"> /** * @return The angle of the unit circle with the image views center */ private double getPositionAngle(double xTouch, double yTouch) { double x = xTouch - mCenterX; double y = mHeight - yTouch - mCenterY; switch (getPositionQuadrant(x, y)) { case 1: return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI; case 2: case 3: return 180 - (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: // ignore, does not happen return 0; } } /** * @return The quadrant of the position */ private static int getPositionQuadrant(double x, double y) { if (x >= 0) { return y >= 0 ? 1 : 4; } else { return y >= 0 ? 2 : 3; } }


下面是重点….很简单先获取象限,然后根据象限获取到弧度值,在把弧度值转换为角度值。获取象限值getPositionQuadrant都应能够看懂,获取角度值的时候有点小问题。数学里面定义的弧度值第一象限是0- π/2,是从x轴开始然后逆时针旋转的值。那么先看1象限的时候:Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;没问题,然后2象限的时候180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);由于是要从x轴开始然后逆时针旋转的值,asin是正值减去一个正值没错;然后2象限的时候180 - (Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI);由于是要从x轴开始然后逆时针旋转的值,asin是负值减去一个负值没错(相当于是180+一个正值);然后4象限的时候360 + Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;由于是要从x轴开始然后逆时针旋转的值,asin是负值加上一个负值没错(相当于360-一个正值)。当然了你可能也注意到了角度的差值是用的touchStartAngle - currentAngle,因为Canvas旋转是相对于x轴进行顺时针旋转….

至于怎么计算指针棒在圆环对应的位置就不详细讲了,看了代码都应该能够明白
先看RotateView

package com.pd.plugin.pd.led.view;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;
import android.widget.Toast;

/**
 * 详情参考 https://github.com/szugyi/Android-CircleMenu/blob/master/circlemenu/src/main/java/com/szugyi/circlemenu/view/CircleLayout.java
 * Created by Tangxb on 2016/8/8.
 */
public class RotateView extends ImageView {
    private int mWidth;
    private int mHeight;
    private float mRadius;
    private float mCenterX;
    private float mCenterY;
    private float angle;
    // Touch helpers
    private double touchStartAngle;
    private boolean didMove = false;
    private int pointX;
    private int pointY;

    public RotateView(Context context) {
        this(context, null);
    }

    public RotateView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RotateView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public RotateView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        mRadius = Math.min(w, h) / 2F;
        mCenterX = mWidth / 2F;
        mCenterY = mHeight / 2F;
    }

    public void setNeedPoint(int x, int y) {
        pointX = x;
        pointY = y;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                touchStartAngle = getPositionAngle(event.getX(), event.getY());
                didMove = false;
                break;
            case MotionEvent.ACTION_MOVE:
                double currentAngle = getPositionAngle(event.getX(), event.getY());
                rotateButtons((float) (touchStartAngle - currentAngle));
                touchStartAngle = currentAngle;
                didMove = true;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                if (didMove) {
                    rotateViewToCenter();
                }
                break;
        }
        return true;
    }

    public void rotateViewToCenter() {
        if (pointX == 0) return;
        BitmapDrawable drawable = (BitmapDrawable) getDrawable();
        Bitmap srcBitmap = drawable.getBitmap();
        Matrix matrix = new Matrix();
        matrix.postRotate(angle, mCenterX, mCenterY);
        Bitmap tempBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(), srcBitmap.getHeight(), matrix, false);
        int color = tempBitmap.getPixel(pointX, pointY);
        // 如果你想做的更细致的话 可以把颜色值的R G B 拿到做响应的处理
        int r = Color.red(color);
        int g = Color.green(color);
        int b = Color.blue(color);
        Toast.makeText(getContext(), "r=" + r + ",g=" + g + ",b=" + b, Toast.LENGTH_SHORT).show();
    }

    private void rotateButtons(float degrees) {
        angle += degrees;
        invalidate();
    }

    /**
     * @return The angle of the unit circle with the image views center
     */
    private double getPositionAngle(double xTouch, double yTouch) {
        double x = xTouch - mCenterX;
        double y = mHeight - yTouch - mCenterY;

        switch (getPositionQuadrant(x, y)) {
            case 1:
                return Math.asin(y / Math.hypot(x, y)) * 180 / Math.PI;
            case 2:
            case 3:
                return 180 - (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:
                // ignore, does not happen
                return 0;
        }
    }

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

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.rotate(angle, mCenterX, mCenterY);
        super.onDraw(canvas);
    }
}

下面是计算指针位置TestFuckActivity:

package com.pd.plugin.pd.led.activity;

import android.os.Handler;
import android.util.DisplayMetrics;
import android.view.Display;
import android.widget.ImageView;

import com.pd.plugin.pd.led.R;
import com.pd.plugin.pd.led.view.RotateView;

/**
 * Created by Tangxb on 2016/8/8.
 */
public class TestFuckActivity extends BaseActivity {
    private RotateView imageView1;
    private ImageView imageView2;
    private int mScreenWidth;
    private Handler mHandler = new Handler();

    @Override
    public int getLayoutResId() {
        return R.layout.layout_fragment_play_three_part02;
    }

    @Override
    protected void initView() {
        imageView1 = getViewById(R.id.iv_color_palette);
        imageView2 = getViewById(R.id.needle);
    }

    @Override
    protected void initData() {
        Display defaultDisplay = getWindowManager().getDefaultDisplay();
        DisplayMetrics displayMetrics = new DisplayMetrics();
        defaultDisplay.getMetrics(displayMetrics);
        mScreenWidth = displayMetrics.widthPixels;
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                int[] location1 = new int[2];
                int[] location2 = new int[2];
                imageView1.getLocationInWindow(location1);
                imageView2.getLocationInWindow(location2);
                int x2 = location2[0];
                int y2 = location2[1];
                int y = y2 + imageView2.getHeight() / 2;
                int x = 0;
                if (x2 > mScreenWidth / 2) {
                    x = imageView2.getWidth() / 2 - location1[0];
                } else {
                    x = imageView1.getWidth() / 2 + x2 - mScreenWidth / 2;
                }
                imageView1.setNeedPoint(x, y);
            }
        }, 200);
    }
}

至于里面的圆环旋转加速度之类的暂时考虑。。。。

以上就是一个很小短但是可以旋转的图片效果的全部内容,请多关注【51DEV】IT技术开发者社区。