Path#opの闇にハマって抜け出せなかった
View作りに欠かせないPath。
API19から追加されたPath#opを触ってみたことについて。
Path#opで何が出来るか
個人的な感覚ですが、異なる2つのPathを引き算したり、UnionしたりXORしたりすることが出来る便利なやつです。
例えば、
このようにPathですべて描画しているものに対して、Bottle内の"中のものが減る"ということを計算して再度座標を計算し直すというのはかなり骨が折れます。
Path#cubicToなどベジェ曲線を使ってる場合はかなりの労力です。
そこで、Path同士の引き算を行うことによって簡単に実現するわけです。
今回の飲み物が増えたり減ったりするAnimationでは以下のようになっています。
mBottleBeerPath.op(mOpPath, Path.Op.DIFFERENCE); mGlassBeerPath.op(mOpPath, Path.Op.DIFFERENCE); canvas.drawPath(mGlassPath, mGlassPaint); canvas.drawPath(mGlassBeerPath, mBeerPaint); canvas.drawPath(mBottlePath, mBottlePaint); canvas.drawPath(mBottleBeerPath, mBeerPaint);
イメージ的には
こんな感じですね。
ハマって抜け出せない闇
Rectでopするとop対象のLinePathが勝手にCloseされて迷惑という話
— あみゅー (@amyu_san) June 23, 2015
コレです。
public class OpSampleView extends View { private Path mMainPath; private Path mOpPath; private Paint mMainPaint; public OpSampleView(Context context) { this(context, null, 0); } public OpSampleView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public OpSampleView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { setUpPaint(); setUpPath(); } private void setUpPaint() { mMainPaint = new Paint(); mMainPaint.setColor(Color.BLUE); mMainPaint.setStyle(Paint.Style.STROKE); mMainPaint.setStrokeWidth(20); } private void setUpPath() { mMainPath = new Path(); mOpPath = new Path(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mMainPath.reset(); mMainPath.moveTo(w / 2, h / 2); mMainPath.lineTo(w / 2 - 300, h / 2 - 300); mMainPath.lineTo(w / 2 + 300, h / 2 - 300); mOpPath.addRect(0, 0, w / 2, h, Path.Direction.CCW); super.onSizeChanged(w, h, oldw, oldh); } @Override protected void onDraw(Canvas canvas) { //mMainPath.op(mOpPath, Path.Op.DIFFERENCE); canvas.drawPath(mMainPath, mMainPaint); } }
このように適当にCloseしてないPathのみで描画した線があります。
当然Closeしていないので三角形は出来上がりません。
別に三角形を作ることを望んでいないので当たり前です。
で、次から問題なことです。
@Override protected void onDraw(Canvas canvas) { mMainPath.op(mOpPath, Path.Op.DIFFERENCE); canvas.drawPath(mMainPath, mMainPaint); }
mMainPath.op(mOpPath, Path.Op.DIFFERENCE);からコメントを外し、左半分を選択しているmOpPathでopすると...
こんな感じに望んでいない形が描画されてしまっているんです...
勝手にCloseされて非常に困ってます。
うーん、コレほんとどうしよう。
これ理由とか解決方法知っている方いたら教えて下さい...
暫定な解決策
線は図形!!!!
がんばって1周させて図形とすればちゃんと描画されます。
最後に
Path#opはかなり便利ですが使えるのがAPI19からというかなり限られています。
そういう微妙に使いづらいところだったり、"op"というググりにくい単語だったりと非常に闇が深くなっています。
ほんと誰か知見ためたら教えて下さい。
コーラ1本上げます。
おわり