Android的ViewGroup.setScaleX()会导致视图被裁剪。

8

我使用NineOldAndroids库来缩放我的自定义布局。

public class MyLayout extends FrameLayout {
  // LayoutParams.MATCH_PARENT and all.
  ...
  @Override
  public boolean setPositionAndScale(ViewGroup v, PositionAndScale pas, PointInfo pi) {
    ...
    mScale = pas.getScale();
    ViewHelper.setScaleX(this, mScale);
    ViewHelper.setScaleY(this, mScale);
  }
}

我已经尝试了FrameLayout和AbsoluteLayout。两者都有相同的效果。 当 mScale < 1.0 时,缩放/缩小功能正常,但布局的一部分被裁剪mScale = 1.0:

mScale = 1.0 mScale < 1.0: 缩放/缩小功能正常,但布局被裁剪

mScale < 1.0 如何解决这个问题? 编辑: 图片是在ICS上拍摄的。所以我认为这不是NineOldAndroids的问题。

你期望输出的样子是什么? - alanv
类似于MapView。使布局(MyLayout)填满整个屏幕,而不像第二张图片中那样被裁剪。MyLayout的布局参数设置为match_parent。 - user802421
5个回答

4

您的视图的父视图必须禁用属性android:clipChildren(可以在布局文件或使用setClipChildren(false)函数实现)。

但是这种方法不能获取视图范围外的触摸事件。您可以通过从活动中发送它们或编写自定义的ViewGroup父级来解决此问题。

我正在使用一种不同的技巧,在我的情况下似乎很有效,诀窍是保持自己的转换矩阵。然后,您必须重载许多ViewGroup方法才能使其正常工作。例如:

@Override
protected void dispatchDraw(Canvas canvas) {
    Log.d(TAG, "dispatchDraw " + canvas);
    canvas.save();
    canvas.concat(mMatrix);
    super.dispatchDraw(canvas);
    canvas.restore();       
}


@Override   
public boolean dispatchTouchEvent(MotionEvent ev) {
    Log.d(TAG, "dispatchTouchEvent " + ev);
    ev.transform(getInvMatrix()); // 
    return super.dispatchTouchEvent(ev);

}

private Matrix getInvMatrix()
{
    if(!mTmpMatIsInvMat)
        mMatrix.invert(mTmpMat);
    mTmpMatIsInvMat = true;
    return mTmpMat;
}

你可以从视图中获取矩阵。view.getMatrix() 然后反转它,m.invert(m),并使用它来缩放运动事件。 - Tatarize
我尝试了几种不同的黑客技巧,从简单地中继原始触摸到由视图矩阵转换的虚假视图。而唯一在我可以访问的所有硬件上始终有效的方法是保持自己的矩阵并使用它来转换motionevents、视图和无效矩形。 - Tatarize

3

如果有人和我遇到了同样的情况,我最终采用了以下方法:

protected void setScale(float scale, boolean updateView) {
    mScale = scale;
    if (updateView) {
        LayoutParams params = getLayoutParams();
        onUpdateScale(scale, params);
        setLayoutParams(params);
    }
}

protected void onUpdateScale(float scale, LayoutParams params) {
    params.leftMargin = (int) (mModel.getX() * scale);
    params.topMargin = (int) (mModel.getY() * scale);
    params.width = (int) (mModel.getWidth() * scale);
    params.height = (int) (mModel.getHeight() * scale);
}

这种方法快吗?我的意思是,您是否使用类似手势缩放的方式进行过多更新,还是一次只缩放一次? - Jorge Gil
我还没有运行基准测试或跟踪视图,但它在Xoom 1和Nexus S上运行良好。要求是移动和缩放需要持续发生(像Google地图),而不是交互结束后才发生(例如缩放OSMTracker)。 - user802421
所以,没有闪烁吗?(如果您回答“没有”,则加1分 :-) ) - Jorge Gil
不幸的是,有时会出现闪烁问题(仅在缩放时)。如果您解决了这个问题,请在此处添加另一个答案 :) - user802421

1

自API Level 11以来,View类具有setScaleX()setScaleY()方法,这些方法按预期工作,并且还可以缩放缩放视图的子视图。因此,如果这对您有帮助,请放弃库并执行以下操作

v.setScaleX(mScale);
v.setScaleY(mScale);

我之前尝试过那个。它有相同的剪辑效果。实际上,该库只是一个代理。在ICS上,NineOldAndroids只是调用了相同的方法。 - user802421

0
使用ViewGroup.layout。这可能是缩放(和移动)ViewGroup最简单的方法。

0
如果我正确理解了您的问题,您正在缩放一个视图组,并期望包含的视图相应地缩放。它不是这样工作的:您缩放视图组并更改其大小,但其子视图不会。

只需缩放所有子视图。即使如此,我也不确定文本和图像是否会自动缩放。您想要的是缩放而不是比例。请尝试this reference


缩放和缩放比例有什么区别?图2显示了缩放/缩放比例的工作方式(mScale〜0.8)。只是ViewGroup被剪裁了。 - user802421
我撤回我的答案,对于造成的干扰很抱歉。 - alexfernandez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接