Android ViewGroup.setLayerType到硬件会导致子视图出现模糊和别名问题
我有复杂的UI,类似于3D棋盘,可以缩放/平移。 为了实现这一点,我们有一个自定义的视图组。但我在这方面遇到了性能问题,比如缩放/平移滞后,因此在搜索while之后,我发现解决方案是使用硬件层支持。必须将我的视图组的图层类型设置为“layer_type_HARDWARE”,这确实解决了性能问题,但也导致了另一个UI质量问题,即:视图组内图像和文本的模糊和锯齿Android ViewGroup.setLayerType到硬件会导致子视图出现模糊和别名问题,android,blur,zooming,antialiasing,hardware-acceleration,Android,Blur,Zooming,Antialiasing,Hardware Acceleration,我有复杂的UI,类似于3D棋盘,可以缩放/平移。 为了实现这一点,我们有一个自定义的视图组。但我在这方面遇到了性能问题,比如缩放/平移滞后,因此在搜索while之后,我发现解决方案是使用硬件层支持。必须将我的视图组的图层类型设置为“layer_type_HARDWARE”,这确实解决了性能问题,但也导致了另一个UI质量问题,即:视图组内图像和文本的模糊和锯齿 public class ZoomLayout extends FrameLayout implements ScaleGestureDe
public class ZoomLayout extends FrameLayout implements ScaleGestureDetector.OnScaleGestureListener, View.OnDragListener {
float x1=0, y1=0, x2, y2;
ScaleGestureDetector scaleDetector;
OnDragListener onDragListener;
Context mContext;
private static final String TAG = "ZoomLayout";
private static final float MIN_ZOOM = 1.0f;
private static final float MAX_ZOOM = 6.0f;
private Mode mode = Mode.NONE;
private float scale = 1.0f;
private float lastScaleFactor = 0f;
// Where the finger first touches the screen
private float startX = 0f;
private float startY = 0f;
// How much to translate the canvas
private float dx = 0f;
private float dy = 0f;
private float prevDx = 0f;
private float prevDy = 0f;
ApiCommunicationListener apiListener;
Activity mActivity;
@Override
public boolean onDrag(View v, DragEvent event) {
return false;
}
private enum Mode {
NONE,
DRAG,
ZOOM
}
public ZoomLayout(Context context, ApiCommunicationListener apiListener, Activity activity) {
super(context);
this.apiListener = apiListener;
this.mActivity = activity;
init(context);
}
public ZoomLayout(Context context) {
super(context);
init(context);
}
public ZoomLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ZoomLayout(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
mContext = context;
scaleDetector = new ScaleGestureDetector(context, this);
}
@Override
public boolean onTouchEvent(final MotionEvent motionEvent) {
ApocketApp.areTwoViewsClicked = false;
switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
x1 = motionEvent.getX();
y1 = motionEvent.getY();
if (scale > MIN_ZOOM) {
mode = Mode.DRAG;
startX = motionEvent.getX() - prevDx;
startY = motionEvent.getY() - prevDy;
}
break;
case MotionEvent.ACTION_MOVE:
if (mode == Mode.DRAG) {
dx = motionEvent.getX() - startX;
dy = motionEvent.getY() - startY;
}
break;
case MotionEvent.ACTION_POINTER_DOWN:
mode = Mode.ZOOM;
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_UP:
x2 = motionEvent.getX();
y2 = motionEvent.getY();
mode = Mode.NONE;
prevDx = dx;
prevDy = dy;
if (x1 == x2 && y1 == y2 && ApocketApp.mViewClicked != null) {
break;
}
scaleDetector.onTouchEvent(motionEvent);
if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
getParent().requestDisallowInterceptTouchEvent(true);
float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
float maxDy = (child().getHeight() - (child().getHeight() / scale)) / 2 * scale;
dx = Math.min(Math.max(dx, -maxDx), maxDx);
dy = Math.min(Math.max(dy, -maxDy), maxDy);
applyScaleAndTranslation();
}
}
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent motionEvent) {
return super.dispatchTouchEvent(motionEvent);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleDetector) {
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
public boolean onScale(ScaleGestureDetector scaleDetector) {
float scaleFactor = scaleDetector.getScaleFactor();
if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {
scale *= scaleFactor;
scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
lastScaleFactor = scaleFactor;
} else {
lastScaleFactor = 0;
}
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector scaleDetector) {
}
private void applyScaleAndTranslation() {
child().setScaleX(scale);
child().setScaleY(scale);
child().setTranslationX(dx);
child().setTranslationY(dy);
}
private View child() {
return getChildAt(0);
}
public void animateToCentre(final RelativeLayout relativeLayout) {
Resources res = mContext.getResources();
TypedValue outValue = new TypedValue();
res.getValue(R.dimen.zoom_centre_level_max, outValue, true);
final float zoomEnd = outValue.getFloat();
ObjectAnimator oaX = new ObjectAnimator();
oaX.setDuration(res.getInteger(R.integer.zoom_centre_duration));
oaX.setFloatValues(new float[]{1.0f, zoomEnd});
oaX.setPropertyName("scaleX");
oaX.setFrameDelay(10);
ObjectAnimator oaY = new ObjectAnimator();
oaY.setDuration(res.getInteger(R.integer.zoom_centre_duration));
oaY.setFloatValues(new float[]{1.0f, zoomEnd});
oaY.setPropertyName("scaleY");
oaY.setFrameDelay(10);
ObjectAnimator oaTy = new ObjectAnimator();
oaTy.setDuration(res.getInteger(R.integer.zoom_centre_duration));
oaTy.setFloatValues(new float[]{0.0f, res.getDimension(R.dimen.v_5) * 3});
oaTy.setPropertyName("translationY");
oaTy.setFrameDelay(10);
AnimatorSet zoomAnimation = new AnimatorSet();
zoomAnimation.playTogether(new ObjectAnimator[]{oaX, oaY, oaTy});
zoomAnimation.setTarget(child());
zoomAnimation.setInterpolator(new FastOutLinearInInterpolator());
zoomAnimation.start();
zoomAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
child().setLayerType(View.LAYER_TYPE_HARDWARE, null);
scale = zoomEnd;
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
}
}