Android甚の独自のビュヌの䜜成-䜕か問題が発生する可胜性はありたすか

「倕方、䜕もありたせんでした」-ズヌム機胜を備えたビュヌを䜜成し、ポむント数に応じおランクごずにナヌザヌを分散させるずいうアむデアが生たれたした。 それ以前は、このレベルの独自のビュヌを䜜成した経隓がなかったため、タスクは初心者にずっおは面癜くお簡単に思えたしたが...

この蚘事では、Android SDKずタスク偎クラスタリングアルゎリズムの䞡方で盎面する問題に぀いお説明したす。 この蚘事の䞻な目的は、いわゆる「カスタムビュヌ」の䜜成方法を教えるこずではなく、䜜成時に発生する可胜性のある問題を瀺すこずです。

このトピックは、このようなものを䜜成した経隓がほずんどないたたはたったくない人、およびAndroid SDKの「柔軟性」を初めお信じる著者の興味を匕く人にずっお興味深いものになりたす。

1.仕組みは


䜜品のデモを芋るGIF


最初に、ビュヌの䜜成方法を簡単に説明したす。
階局独自のビュヌは緑色でマヌクされおいたす



RankingsListView

テヌブルの先頭には、 RankingsListView  ScrollView埌継がありたす。 スクロヌルを管理し予期せず、ハァッ、ズヌムし、たた、 RankingViewからリストを䜜成したす。

RankingView

RankingViewはランク巊ずUsersView 右が衚瀺されたす。

UsersView

UsersView 、ごUsersView 、ナヌザヌの衚瀺ず、ナヌザヌをグルヌプに結合および分離するアニメヌションの衚瀺に取り組んでいたす。

GroupView


ナヌザヌずナヌザヌグルヌプの䞡方がGroupViewず呌ばれる単䞀のビュヌに衚瀺されGroupView 。 グルヌプではなく1人のナヌザヌが衚瀺されおいる堎合にのみ、緑色の円はありたせんその䞭にグルヌプ内のナヌザヌ数が衚瀺されたす。 さお、右偎には「」蚘号の付いたナヌザヌ/グルヌプスコアむンゞケヌタヌがありたす。

おそらく退屈な郚分で、私たちは問題に目を向けたす。

ps 「結論」の゜ヌスぞのリンク。

2. Android SDK「あなたずゲヌムをプレむしたい」©Goog ...芋た


無害な状態から始めたしょう。

2.1。 DataBindingを䜿甚しおカスタムView内でマヌクアップを膚匵させる


DataBindingずそのコヌド生成は驚くべき働きをしたす

 WidgetGroupViewBinding binding; 
 binding = DataBindingUtil.setContentView(this, R.layout.activity_main); // binding.title    

このマヌクアップがどんなに耇雑であっおも、マヌクアップに瀺されおいるすべおのビュヌはidによっお2行およびbinding倉数を介しおアクセスできたす。 これ以䞊

 @ BindView (R.id.tb_progress) View loadingView; @BindView (R.id.tb_user) View userView; @BindView (R.id.iv_avatar) ImageView avatarView; @BindView (R.id.tv_name) TextView nameView; @BindView (R.id.l_error) View errorView; @BindView (R.id.l_container) ViewGroup containerLayout; 

...そしお、 ButterKnifeような12行以䞊。 しかし、ちょっず埅っおください setContentView()はActivityメ゜ッドです。 そしお、ビュヌは䜕をしたすか

珟圚のビュヌ内にマヌクアップを远加するには、コンストラクタヌ内などでinflate(getContext(), R.layout.my_view_layout, this)メ゜ッドinflate(getContext(), R.layout.my_view_layout, this)を呌び出す必芁がありたす。 最埌のフラグは興味深いです。 珟圚のビュヌにマヌクアップビュヌを远加したす。 これにより、マヌクアップで䟋えばLinearLayoutなどのルヌトタグがあり、 LinearLayoutから継承されたビュヌ内でinflate(
)を䜿甚しようずするず、階局内に2぀のLinearLayoutが取埗されたす...

...これは、 LinearLayoutの1぀が冗長であるため、快適ではありたせんが、非垞に論理的です。 どうする これを回避するのは簡単です。 ここで説明するように 、マヌクアップ内で<merge>を䜿甚しお、ビュヌ内にあるべきすべおのものでラップする必芁がありたす。

しかし DataBindingは<merge>サポヌトしたせん。 そのルヌトタグは<layout>である必芁があり、その内郚には<merge>ではなく単䞀の子芁玠が存圚する必芁がありたす実際、 <data>も存圚する可胜性がありたすが、これはたったく別の話です。

その結果、珟時点では、远加のレむアりトを䜜成せずに独自のビュヌでDataBindingを䜿甚する方法はありたせん。これは、パフォヌマンスに最良の圱響を䞎えたせん。 ButterKnifeはただ私たちのすべおです。

UPD  code.google.comでの機胜リク゚スト 。

2.2。 枬定ずレむアりトのパス


ビュヌの䜜成経隓がなかったにもかかわらず、このトピックに関する人目を匕く蚘事を時々読んでおり、 「ビュヌがどのように描かれるか」ずいうトピックに関するドキュメントのセクションも芋たした。 埌者を信じるなら、すべおが可胜な限り単玔です


たあ非垞に簡単です。 このため、私自身の芋解を実珟するこずは難しくないず信じおいたした。 しかし、それはありたしたネタバレ著者は、本文の埌半のonLayoutメ゜ッドから倧きな問題を぀かむでしょう。 ビュヌを䜜成した埌に掚枬したヒントずルヌルのリストを次に瀺したす。


ビュヌのトピックに぀いお読んだ蚘事では、これらのメ゜ッドのそのような説明を芋たこずはありたせん。 これに遭遇しないか、これがカスタムビュヌクラブの最初のルヌルですonLayout() 陀倖;䜿甚枈みに぀いおは話さないでください。

私の堎合、 UsersView.onLayout()内で、ビュヌのY座暙が倉化したす。これにより、䞀郚のビュヌが衚瀺され、他のビュヌが非衚瀺になり、...に぀ながりたす右䞋に泚意。


...底面図をクリップしたす。 これは遠く離れたずころでのみ起こりたした。 私は愚かにいじくり回さなければなりたせんでしたが、嚘のビュヌは、珟圚の䜍眮Yでは芪に半分しか衚瀺されないず刀断したようです。したがっお、 Bitmap drawingCache;トリミングできたすBitmap drawingCache; 。 ここで、 measureChildren()内のonLayout()の圢で、非垞に远加の「枬定パス」が助けになりたした。これにより、ビュヌはY座暙を倉曎した埌にキャッシュを再怜蚎したした。

2.3。 ScrollViewは子のScrollView蚱可したせん


おそらく、あなたの倚くは、 layout_height=match_parent ScrollView芁玠の高さを蚭定する必芁に遭遇し、即座に倱敗したした。結果はwrap_content堎合ず同じであったため、 fillViewportフラグの説明があるこのような蚘事を芋぀けたしたか そしお今、質問 fillViewportフラグず同じ結果を達成するが、子の高さを動的に倉曎する方法は

順番に行きたしょう。 芁玠の高さをどのように倉曎できたすか もちろん、 LayoutParams.heightを通じお、これ以䞊䜕もしたせん。 問題は解決したしたか いや 高さは倉曎されおいたせん。 どうしたの 子ビュヌでonMeasure()を怜蚎した結果、 ScrollView単にパラメヌタヌの蚭定heightれたheightを無芖し、たず「 UNSPECIFIED 」に等しいmode onMeasure()を送信し、次に「 EXACTLY 」およびheight倀でonMeasure()を送信するずいう結論に達したした。 ScrollViewのサむズに等しい fillViewport蚭定されおいる堎合。 たたheightビュヌのheightを倉曎する唯䞀の方法はそのLayoutParamsを倉曎するこずなLayoutParams 、子は倉曎されたせん。

私は2぀の解決策を芋぀けたした

  1. ScrollView非垞にLayoutParams 、 LayoutParamsを無芖するため、 onMeasure()メ゜ッドを曞き換えお、 onMeasure()を远加するこずができたす。

     if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED && getLayoutParams().height > 0) { heightMeasureSpec = MeasureSpec.makeMeasureSpec( getLayoutParams().height, MeasureSpec.EXACTLY); } 

    したがっお、 ScrollViewを圌のために機胜させたす。 しかし、これのために毎回サブクラスを䜜成するのは自然です-良い考えではありたせん。 子FrameLayoutがどのクラスである必芁があるかはわかりたせん FrameLayout 、 LinearLayout 、 RelativeLayoutなど。 可胜な各Layoutずサブクラスに察しお行うには-ごみ。 したがっお、ここに゜リュヌション番号2がありたす。

  2. 子をFrameLayoutラップし、このFrameLayout子のサむズを倉曎したす。

私が䜿甚したそのアプロヌチ番号2、そしおそれはバタンず働いた。 ただし、これが本圓に有効な方法ハックかどうかはわかりたせん。 远加のFrameLayout は FrameLayout 尊重するため、おそらくこのハックは機胜したせんが、 ScrollView.onLayout()内ではあらゆる ScrollView.onLayout() ゲヌムが発生し、子のサむズを郚分的にしか蚈算したせん。 これは単なる掚枬に過ぎたせんが、スクロヌルの問題を説明するこずはできたせんネタバレ問題に぀いおは埌で説明したす。

そうそう、 ScrollView にはバグトラッカヌ䞊の子䟛の䞍倉のサむズに問題がありたすが、Androidで通垞発生するように、2014幎以降は新しいステヌタスのたたです。

2.4。 background近くの䞞い角


被隓者巊䞋ず巊䞊


それはもっず簡単に芋えるかもしれたせん- <shape>でdrawableし、 backgroundを蚭定すればdrawableです... タスクは、色がプログラムで倉曎され、䞞みを垯びた゚ッゞが最初ず最埌の芁玠にのみ远加されるこずです。

奇劙なこずに、 ShapeDrawableクラスにShapeDrawable 、予想されるように䞞い角を操䜜するためのメ゜ッドがありたせん。 しかし、幞いなこずに、 RoundRectShapeずPaintDrawable盞続人このクラスが必芁な理由-尋ねないでください、あなたはショックを受けおいたすには、欠萜しおいるメ゜ッドがありたす。 これにより、ほずんどすべおのアプリケヌションの問題は解決されたず芋なされたすが、このタスクの問題ではありたせん。

タスクの詳现は、最倧のzoom inが䜕でも可胜であるずいうこずです。぀たり、 backgroundビュヌが匕き䌞ばされ、...
Logcat: W/OpenGLRenderer: Path too large to be rendered into a texture
䞀定のサむズを超えるず、 backgroundが衚瀺されなくなるだけです。 譊告からわかるように、䞀郚のPath倧きすぎおテクスチャに描画できたせん。 情報源を少し調べおみるず、この同志がすべおを責めるこずになっおいるずいう結論に達したした。

 canvas.drawPath(mPath, paint); 

... mPath角䞞長方圢が配眮されたす。

 mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW); 

この問題を解決するには、たずえばColorDrawableを継承し、 drawPath()呌び出さずにdraw()メ゜ッドを呌び出したす。

 canvas.clipPath(roundedPath); 

しかし、残念ながら、このアプロヌチには比范的重倧な欠点がありcanvas.clipPath()  canvas.clipPath()アンチ゚むリアスの圱響を受けたせん 。 ただし、これを行う別の方法がない堎合、これに満足する必芁がありたす。

2.5。 FrameLayout内にViewをFrameLayout


UsersViewを実装しようずするず、このタスクに盎面したした。その䞭で、GroupViewはOY軞に沿った任意の堎所に配眮できたす。

最初に思い浮かんだのはそしおFrameLayout内でビュヌを移動する唯䞀の可胜な方法だず思ったこず、 topMarginを䜿甚しおtopMarginパラメヌタヌを倉曎するこずtopMargin 。 これは、stackoverflowに察するほずんどの回答1、2、3によっお蚌明されおいたす。

このアプロヌチの欠点は、 LayoutParamsを倉曎するずrequestLayout()が呌び出されるこずです。これは、レむアりトパス自䜓がより良い時間次の16msフレヌムたで遅延しおも、特にGroupView内のすべおのGroupViewに察しお呌び出される堎合、非垞に高䟡な操䜜です。

しかし、幞いなこずに、別の方法がありたすView.setY()  stackoverflowぞの回答 。 アニメヌションや、䞍倉のLayout内の子䟛に最適です。 requestLayout()呌び出したせんが、ビュヌ自䜓のフィヌルドのみを䜿甚し、パスレむアりトのフェヌズのみに圱響したす。 たた、新しいビュヌ䜍眮の蚈算onLayout()は、 onLayout()を呌び出す前にonLayout()盎接行われるため、 requestLayout()はたったく必芁ありたせん。

2.6。 フォントのむンデントを確認したすか いや そしお圌らはあなたを芋る © includeFontPadding


ナヌザヌがグルヌプに結合されるず、グルヌプ内のナヌザヌ数を衚瀺するアむコンが远加されたす。 圌女は次のようになりたす。



そしお、これが圌女の以前の姿です。



違いに気づきたしたか 2枚目の写真を芋るず䞍快感はありたすか もしそうなら、あなたは私を理解しおいたす。 長い間、このアむコンを芋るず、思ったほど魅力的に芋えない理由を理解できたせんでした。 ペむントを拟っお、テキストの巊/右/侊/䞋のピクセル数を蚈算するず掚枬しお、私は理由を理解したした-テキストは䞭倮に配眮されおいたせん。 テキストの重芁性に関しお明らかに䜕かが間違っおいたす。 はい..いいえ 重力が正しく蚭定され、他のパラメヌタヌも蚭定されたした。 すべおが完璧に芋えたした。

䞀般に、私は苊しむこずはありたせん、解決策は非垞に簡単であるこずが刀明したしたが、それをたったく理解しおいなかったずいう理由だけですぐに芋぀けるこずができたせんでした。 ずころで、ここに、゜リュヌションぞのリンクがありたす 。 芁するに、フォント自䜓にはパディングがあり、それが非䞭倮揃えの理由でした。 includeFontPadding=falseパラメヌタヌをTextViewに远加するず、問題は完党になくなりたした。

2.7。 ViewPropertyAnimatorはreverse()メ゜ッドがありたせん


ランクアむコンを特定のサむズで非衚瀺にするアニメヌションを䜜成したかったのです。 次のようになりたす。


アニメヌションの開始時間を決定するには、珟圚のサむズをすべおのビュヌに合わせお必芁なサむズず比范し、必芁に応じおview.animate().setDuration(fadeDuration).alpha(0 or 1)たす。

ただし、これは高速fadeアニメヌションでのみ有効です。 ただし、 fadeが遅い堎合、 zoom out埌にシャヌプにzoom inず、ビュヌのアルファチャネルは1たたは0ではなく、たずえば0.5になりたす。 そのため、アニメヌションは同じfadeDurationに察しお0.5から0たで再生されたす。 アニメヌションが2倍遅くなったように芋えたす。 view.animate()呌び出す前にview.setAlpha(0 or 1)ようなものを远加するのは良い解決策ではありたせん。 ビュヌは高速ズヌムでちら぀き始めたす。

理想的には、 setReverseDuration() パラメヌタなしsetReverseDuration()の圢匏のメ゜ッドがあるはずです。これは、「ええ、 fadeアニメヌションを500 setReverseDuration()再生したので、リバヌスアニメヌションも同じ量を再生したす」。 しかし、これは残念なこずではありたせん。 私が芋぀けた唯䞀の方法は、ペンでそのようなこずをするこずでした。 私の堎合、アニメヌションは非垞にシンプルだったので、これで私は非衚瀺にできたした

 final float realDuration = iconView.getAlpha() * animationDuration; 
...そしおこれはショヌのために

 final float realDuration = (1 - iconView.getAlpha()) * animationDuration; 

それでは、い぀ものように view.animate().setDuration((long) realDuration) -それだけです。

UPD  code.google.comでの機胜リク゚スト 。

2.8。 ScaleGestureDetector 別名「ピンチ」、別名「ズヌム」


ScaleGestureDetector API ScaleGestureDetector非垞に優れおいlistenerをハングさせおむベントを埅機し、すべおのonTouchEvent()ディテクタヌ自䜓onTouchEvent()枡すonTouchEvent()ください。 しかし、すべおがそれほどバラ色ではありたせん。

2.8.1。 小さなメモ


たず、 ScaleGestureDetector自䜓ずScaleGestureDetector間でonTouchEvent()むベントを区別する方法はどこにも蚘茉されおいたせん結局、 ScrollViewの子孫であるRankingsListView内で発生したす。 その結果、メ゜ッドは次のようになりたす。

 @Override public boolean onTouchEvent(MotionEvent ev) { scaleDetector.onTouchEvent(ev); super.onTouchEvent(ev); return true; } 

したがっお、すべおのstackoverflow-answers 䟋 を実行するこずをお勧めしたす。 ただし、このアプロヌチには欠点がありたす。 ピンチしおもスクロヌルは発生したす。 些现なこずのように思えるかもしれたせんが、実際、芋栄えをよくしようずしたずきに誀っおビュヌをめくっおしたうのは非垞に䞍快です。

super.onTouchEvent()ずscaleDetector.onTouchEvent()間の責任を区別する耇雑な゜リュヌションを探すための長くお退屈な怜玢を探す準備ができおいたした...そしお実際に怜玢したした...しかし、結果は非垞にシンプルでした

 @Override public boolean onTouchEvent(MotionEvent ev) { scaleDetector.onTouchEvent(ev); if (ev.getPointerCount() == 1) { super.onTouchEvent(ev); } return true; } 

玠晎らしいですね super.onTouchEvent()は、最初にsuper.onTouchEvent()しid指のid远跡しないため、指1でスクロヌルを開始し、指2でスクロヌルを終了しおも、倧䞈倫です。 残念ながら、Android SDKが再びホむヌルにスティックを入れるこずを確信しおいたので、゜ヌスをグヌグルで調べおみお、これを詊しおみたした。 私が蚀えるこずは、Android SDKは時には驚きずしお機胜するこずです。

第二に 、もしあなたがミクロ最適化疟患に苊しんでいるなら、あなたは子䟛の意芋の​​倧きさを泚意深く監芖する必芁がありたす。 既にご存知のように、ピンチでScrollView子の内偎の子の高さをScrollViewたす。 この子はLinearLayout 、その子はlayout_weight=1蚭定されたす。 蚀い換えるず、それらはすべお同じ高さです...ではありたせん。

これはたったく目立぀こずはありたせんが、ピクセルは原子単䜍であるため、その子ビュヌは垞に同じ高さになるずは限りたせん。 ぀たり、 LinearLayoutの高さが1001で、子が2぀ある堎合、そのうちの1぀は501で、もう1぀は500です。これを目で確認するこずはほずんど䞍可胜ですが、間接的な結果が生じる可胜性がありたす。

ViewPropertyAnimatorずreverse()に぀いお話したずき、ランクアむコンを非衚瀺にするアニメヌションを瀺したした。 チェック自䜓は簡単TextView 。2぀のTextViewずImageView高さをonLayout()にたずめ、それらが䞀床に珟圚のビュヌに収たらない堎合は、 fadeのImageView非衚瀺にしImageView 。 たた、この合蚈の高さいわゆる「高さのしきい倀」が倉わらないこずにも泚意しおください。 その結果、しきい倀が500ピクセルの堎合、説明されおいるケヌスでは、500ビュヌサムネむルの1぀がアむコンで非衚瀺になり、2番目の501サむズは非衚瀺になりたす。

状況はたれであり、あたり重芁ではありたせん非衚瀺でないアむコンず非衚瀺のアむコンを同時に怜出するためにマりスを非垞にゆっくり動かすのはそれほど簡単ではありたせんでした難しくはありたせんでした。 ただし、この動䜜が気に入らない堎合は、修正する方法は1぀しかありたせんgetHeight()を䜿甚しおしきい倀ず照合しないでください。 onSizeChanged()内のonSizeChanged() 、すべおの子の最小サむズを芋぀け、党員にこの数倀ずしきい倀を比范するよう通知したす。 私はそれをshared heightず呌び、私にずっおはこのように芋えたす

 private void updateChildsSharedHeight() { int minChildHeight = Integer.MAX_VALUE; for (int i = 0; i < binding.lRankings.getChildCount(); ++i) { minChildHeight = Math.min(minChildHeight, binding.lRankings.getChildAt(i).getMeasuredHeight()); } for (int i = 0; i < binding.lRankings.getChildCount(); ++i) { RankingView child = (RankingView) binding.lRankings.getChildAt(i); child.setSharedHeight(minChildHeight); } } 

たた、しきい倀ずの調敎自䜓は次のずおりです。

 int requiredHeight = binding.tvScore.getHeight() + binding.tvTitle.getHeight() + binding.ivIcon.getHeight(); boolean shouldHideIcon = requiredHeight > sharedHeight; 


UPD  code.google.comでの機胜リク゚スト 。

2.8.2。 問題


そしお、 ScaleGestureDetectorに぀いおのScaleGestureDetectorではなく、その問題に぀いお話したしょう。

2.8.2.1。 最小ピンチ



I and and and and and and and and-fro ...圌最小ピンチは無効になりたせん。 コヌディング䞭に、「ピンチをトリガヌするための最小距離」に぀いおはただ知りたせんでしたので、ログを少し調べお、これがコヌドの劚害か䜕かを確認する必芁がありたした。 ログによれば、指の間の距離が510ピクセル未満の堎合、 ScaleGestureDetector単にタッチぞの応答を停止し、 onScaleEnd()むベントを送信したす。 䜕らかの皮類の「最小限のピンチ」があるずいう情報は、ドックにもスタックオヌバヌフロヌにも存圚したせんでした。 ゚ミュレヌタでデバッグが行われなかった堎合、おそらく私はこれに気付かないでしょう。 その䞊で、ピンチ距離は少なくずもミリメヌトルである可胜性があり、これが問題に関する情報を芋぀ける理由ずなりたした。 しかし、それは私が思っおいたよりずっず近いこずがわかりたした。

 mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan); 

そしお、そしお、そしお、そしお、そしお、そしお、そしお、そしお、そしお、そしお、そしお、スルヌを通しおcom.android.internal.R.dimen.config_minScalingSpanもちろん、このクラスは、このフィヌルドを倉曎する方法を持たず、もちろん、 com.android.internal.R.dimen.config_minScalingSpanは、魔法の27mmに等しい 私にずっお、最小限のピンチの存圚は非垞に奇劙な珟象のようです。 このように意味があったずしおも、それを倉曎する機䌚を䞎えおみたせんか
通垞の問題の解決策は、リフレクションです。

2.8.2.2。 坂道


「私」のような「ずさん」が䜕であるかを知らない人のために、私は翻蚳したす
スロップ-ナンセンス、ナンセンス©ABBYY Lingvo

さお、冗談はさおおき。「スロップ」ずは、ナヌザヌが誀っお画面に觊れお、実際に移動/スクロヌル/ズヌム/その他のものを望んでいないず思われる状態です。䞀皮の「偶発的な動きに察する保護」。GIFの説明


... gifでは、ピンチの開始前に、ピンチずは芋なされない最小限の動きが蚱可されおいるこずがわかりたす。原則ずしお、良いこずに加えお。

しかし...スロップも倉曎できたせんScaleGestureDetector次のように説明したす。

 mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2; 
...などViewConfigeuration

 mTouchSlop = res.getDimensionPixelSize( com.android.internal.R.dimen.config_viewConfigurationTouchSlop); 

この意味はどこから来たのですか なんで なんでそれは䞍明です...䞀般的に、Android SDKは最高のリフレクションチュヌトリアルです。

UPDcode.google.comのSlop / Spanの機胜リク゚スト。

2.8.2.3。detector.getScaleFactor()最初のピンチレヌス


むベント内onScale(ScaleGestureDetector detector)で送信され、detectorメ゜ッドを䜿甚detector.getScaleFactor()しおピンチ係数を芋぀けるこずができたす。したがっお、最初のピンチでは、このメ゜ッドは奇劙なゞャンプのような倀を返したす。厳密な移動䞭の倀のログはzoom out次のずおりです。芋た目は、それほどではありたせんが、ビュヌのサむズは垞にぎくぎくしおいたした。アニメヌションでこれらのゞャンプをどのように芋るかは、完党に省略する方が良いでしょう。長い間、私は問題が䜕であるかを理解しようずしたした。実際のデバむスで確認し突然、゚ミュレヌタヌの問題が発生するこずはわかりたせん、猫が1ミリメヌトル䜙分に死んでいるかのようにマりスを動かしたしたたったくわからないので、突然、けいれんしお、ログを蚘録したす-しかし、そうではありたせん。答えは芋぀かりたせんでしたが、幞運でした。「ブルドヌザヌから」ず蚀うために、むベントに送るこずを決めたした

0.958
0.987
0.970
1.009
0.966
0.967
1.006




. > 1ScaleGestureDetectorMotionEvent.ACTION_CANCEL 初期化盎埌

 scaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); long time = SystemClock.uptimeMillis(); MotionEvent motionEvent = MotionEvent.obtain(time - 100, time, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); scaleDetector.onTouchEvent(motionEvent); motionEvent.recycle(); 

...そしおそれはO_oの助けになりたした...゜ヌスコヌド、Android SDKでいろいろ調べたした。゜ヌスコヌドでは、最初のピンチにはスロットがありたせんでしたはい、これは䞊蚘のものです。なぜこれなのか-私にずっおは、このハックが助けたのず同じように、謎のたたです。おそらく、圌らは初期化で決心したどこかで、クラスの䞀郚は最初のピンチがすでにスロップテストに合栌したず考え、他の郚分はそうではないず考え、その結果、「合栌/倱敗」タむプの熱い戊いの熱䞭に、それら。¯\ _ツ_ /¯©SDK

UPDcode.google.comのバグレポヌト。

2.9。ScrollView.setScroll()埌にのみ動䜜しsuper.onLayout()たすか


ScrollView子どもたちheightの集合を無芖する問題に戻りたす。状況は次のずおりです。ピンチが発生するずすぐに、珟圚のフォヌカスマりスをクリックした堎所ずズヌムを行うポむントを同じたたにしたいず思いたす。なんで ちょうどそのように、ズヌムはよりナヌザヌフレンドリヌに芋えたす。子芁玠の高さを倉曎するだけでなく、他のすべおのナヌザヌが圌から離れる間に、䞀郚のナヌザヌにズヌムむンするこずを考慮しおください。


それは難しいこずではありたせん確認したすScaleGestureDetector.getFocusY()ずScrollView.getScrollY()。それからScrollView.setScrollY(newPosition)、垜子の䞭でそれを行うのに十分であるように思われたす...しかし、いいえ、ビュヌは最も䜎い子芁玠ぞのズヌムで奇劙にひき぀り始めたす


ここで解決策が芋぀かりたした。次のようになりたす実行した時点でsetScroll()、スクロヌル䜍眮が子芁玠のサむズを超えおいないかどうかを確認し、超えおいる堎合は可胜な最倧䜍眮を蚭定したす。たた、setScroll()ズヌムで呌び出されるため、次の䞀連のアクションが取埗されたす。

  1. newHeightのカりント
  2. newScrollPosのカりント
  3. setLayoutParamsでnewHeightを蚭定したす
  4. setScrollでnewScrollPosを蚭定したす

問題は段萜番号3にありたす。実数heightは次の倀たで倉曎されないsuper.onLayout()ため、setScroll()期埅されるこずは実行されたせん。以䞋のように修正されたす。代わりに、setScroll()これを行いたす

 nextScrollPos = newScrollY; 
...そしおonLayout()afterメ゜ッドでsuper.onLayout()このメ゜ッドを呌び出したす

 private void updateScrollPosition() { if (nextScrollPos != null) { setScrollY(nextScrollPos.intValue()); nextScrollPos = null; } } 

芚えおいるように、の埌にメ゜ッドを呌び出さない方が良いず曞きたしたsuper.onLayout()。これはただ事実です。埌で、この゜リュヌションに関連する別の問題に぀いお説明したす。しかし、事実は残っおいたす。これはスクロヌルゞャンプの問題の解決策です。

psただし、「height子内郚の子の倉曎」でハックを䜿甚しない堎合、ScrollViewこのような問題は発生したせん。しかし、その埌、12個のサブクラスの問題に戻りたす。

3.ナヌザヌをクラスタリングするタスク


ここで、タスク自䜓、アルゎリズム、およびその機胜の䞀郚に぀いお説明したす。

3.1。 囜境ナヌザヌをどうするか


私は圌らのランクの境界にいるナヌザヌに぀いお話しおいる


図では、境界ナヌザヌはポむント0、30、85のナヌザヌですナヌザヌは80のナヌザヌによっおほが完党にブロックされたした。最も簡単な方法は、それらを正しい䜍眮に描画するこずです以䞋ず同等h e i g h t ∗ s c o r e / 100、しかし、この堎合、他の人のランクに萜ち始めたす。これを拒吊する䞻な理由はグルヌプ化です。 29のポむントを持぀ナヌザヌを想像しおください。圌は「初心者」のランクの境界にいたす。しかし、今では圌は突然33のポむントを持぀ナヌザヌず結合し、それらのゞョむントグルヌプは31に察応する䜍眮、぀たり「良い」ランクに配眮されおいたす。ビュヌのグルヌプがナヌザヌのランクを倉曎できるずいう考えがあたり奜きではなかったので、私はそれを拒吊し、䞊の写真で芋たようにランク内のナヌザヌを制限するこずにしたした。

今埌、グルヌプ化アルゎリズムずアプリケヌション党䜓のロゞックに倚くの問題が远加されるこずに泚意しおください。

3.2。 グルヌプにはいく぀のポむントがありたすか


ポむントが40ず50の2人のナヌザヌがグルヌプに統合されたずしたす。共同グルヌプをどこに配眮し、どのようなポむントで配眮したすか答えは簡単です。グルヌプは45で、䜍眮はグルヌプポむントに察応しおいたす。

タスクを耇雑にしたしょう。そしお、これらをどのように組み合わせるのですか



ここには2぀の解決策がありたす。

  1. ナヌザヌ40および50ず同じです。぀たり、グルヌプを2.5の䜍眮に配眮したす。
  2. グルヌプを定䜍眮に眮く (view1.positionY–view2.positionY)/2 , .

アプロヌチの違いは、最初のケヌスではグルヌプビュヌがナヌザヌビュヌの䞭倮に配眮されないこずです。2番目のケヌスではグルヌプ化が䞭倮に配眮され、ナヌザヌ゚クスペリ゚ンスの芳点からはるかに有利です。UXを

優先しお、私は2番の方法でそれを行うこずにしたしたが、このアプロヌチは重倧な欠点を明らかにしたした。グルヌプポむントは完党に曲がっお蚈算されたす。実際、0のナヌザヌは実際には䜍眮0に䜍眮しおいないその堎合、他の誰かのランクのテリトリヌに入ったためので、ランク内のすべおのビュヌがsomeよりも少ないポむントを持぀こずはできたせん。たた、ズヌムによっお倉化したす。これは、匏簡易バヌゞョンによっお蚈算されるためです。minScore

m i n S c o r e = u s e r V i e w H e i g h t / c o n t a i n e r H e i g h t ∗ r a n k S c o r e M a x


... userViewHeight倉曎されおいないが、containerHeight倉曎されおいるため、ピンチの異なるポむントで境界ビュヌのポむントが異なる。
さらに、匏自䜓

viewGroup.positionY=(view1.positionY–view2.positionY)/2


...䞞め゚ラヌが発生したす 䜍眮はピクセル単䜍で枬定され、これによりポむント数の最埌の桁にランダム性が远加されたす実際、すべおはそうではありたせん。䜿甚される堎合、ピクセルではなく、view.getY()戻りたす。floatすべお䜿甚MarginLayoutParams.topMarginされる堎合、゚ラヌが発生したす。

方法No. 2のこれらすべおの欠点を考慮するず、方法No. 1を䜿甚するこずが決定されたしたが、グルヌプビュヌはナヌザヌビュヌ間の䞭倮に正確には衚瀺されたせん。

3.3。 アルゎリズム


それはあなたが歩き回るこずができるずころです。 私がやった。少なくずも5぀の異なる実装があり、「䞍快な」効果によっお䜕らかの圢で圱響を受けおいたため、新しい方法で䜕床も問題を解決する必芁がありたした。

最終的な実装を蚘述しおこれを完了するこずはできたすが、実装のいく぀かを説明するこずをお勧めしたす。以䞋に説明するクラスタリングの問題に興味がある堎合は、それをどのように解決するかどのアルゎリズムを発明/䜿甚するかを考えおから、パラグラフごずに読んでください。私のように、アヌティファクトが発生しやすい堎合は決定を倉曎しおください。

3.3.1。挑戊する


優れたUXを䜿甚しおクラスタリングを行いたす。

  1. 境界ビュヌはランク内に留たる必芁がありたす。
  2. – , zoom in zoom out zoom in - .
  3. / ( №2).

3.3.2.


アルゎリズム自䜓を開始する前のすべおの実装では、すべおのナヌザヌはポむントで゜ヌトされ、Group実際には1人のナヌザヌが1人のグルヌプであるため、各ナヌザヌがクラスに倉わるこずに泚意するこずが重芁です。たた、「ナヌザヌ」ずいう蚀葉を䜿甚するず、グルヌプに参加する前の1人のナヌザヌず、ナヌザヌのグルヌプの䞡方を意味できたす。

衚蚘に぀いお。ナヌザヌの番号に1぀の番号「7」を付け、グルヌプに2぀の番号「78」を付けたす。グルヌプ番号の数字は、それに含たれるナヌザヌの数を瀺したす。぀たり、グルヌプ78はナヌザヌ7ず8で構成されたす。

各アルゎリズムには、蚀葉による説明ず擬䌌コヌドの䞡方が䞎えられたす。

3.3.3。アルゎリズム番号1


ナヌザヌが亀差する堎合、ナヌザヌを順番に結合する単玔な順次アルゎリズム。

手順

1. , i i+1.
2.1. – №1.
2.2. , .
3. 1 .


 for (int i = 0; i < groups.size() - 1; ) { if (isInersected(groups[i], groups[i+1])) { groups[i].addUsersToGroup(groups[i+1]); groups.remove(i+1); } else { ++i; } } 

ただし、このアルゎリズムにはUXに問題がありたす。


最初は十分に近い堎合、すべおのナヌザヌを結合したす。これは、スペヌスの䞍合理な䜿甚に぀ながりたす。぀たり、アルゎリズムはUXに適合したせん。

3.3.4。アルゎリズム番号2


明らかに、問題はすべおのナヌザヌが順番にチェックされるこずです。そのため、アルゎリズム番号1をわずかに倉曎するこずにしたした。これで、ナヌザヌのリストには少なくずも2぀のパスがありたす。偶数パスず奇数パスです。䞡方のパスで亀差点が芋぀からないずすぐに、アルゎリズムは終了したす。

手順
0. i = 0.
1. , i i+1.
2.1. – , . 1.
2.2. , 2.
3. , 1.
4. i == 1 , .
5. 0, i ( 0 1 1 0 – ).


 bool didIntersected, isEvenPass = false; do { didIntersected = false; isEvenPass = !isEvenPass; int i = isEvenPass ? 0 : 1; while (i < (groups.size() - 1)) { if (isInersected(groups[i], groups[i+1)) { didIntersected = true; groups[i].addUsersToGroup(groups[i+1]); groups.remove(i+1); i += 1; } else { i += 2; } } } while(isEvenPass || didIntersected); 

このアルゎリズムは以前の問題を解決したすが、結合埌の䞍正確な切断に関連するズヌム速床が異なるため新しい問題が発生したす。この問題を「問題21-12」ず呌びたす名前に぀いおは埌で説明したす。


ここで䜕が起こったのかを説明したす。アルゎリズムを実行するず、1人ず2人のナヌザヌが亀差しおグルヌプを圢成するこずが明らかになりたした。3番目のナヌザヌはグルヌプず亀差するため、すべおが別のグルヌプを圢成したす。

ただし、より速いズヌムでそれらを解陀しようずするず、画像の䞋郚に衚瀺されるものが発生したす。2人のナヌザヌは亀差したすが、グルヌプを圢成したせん。

結合の別の実行を分割した埌でも、以前は存圚しなかったグルヌプ23を取埗したす。以前は、ナヌザヌはサむズ2ず1のグルヌプに統合されおいたしたが、今では、分離埌、ナヌザヌはサむズ1ず2のグルヌプを圢成しおいたす。したがっお、名前は「問題21-12」です。これは、ズヌム速床に応じおグルヌプがさたざたな方法で結合される堎合、UXにずっおは悪いこずです。぀たり、アルゎリズムが適合したせん。

3.3.5。アルゎリズムNo. 3


それから、額の䞭で問題を愚かに解決するこずは䞍可胜であり、より重い砲を䜿甚しなければならないこずが明らかになりたした。したがっお、ナヌザヌ間の距離ビュヌに基づいおナヌザヌを結合するこずにしたした。ナヌザヌ間の距離が小さいほど、最初にナヌザヌが関連付けられたす。たた、グルヌプを分割するには、タむプフィヌルドStack<Group> groupsStack;を入力しお、そこに新しいグルヌプをすべお远加したす。したがっお、切断するずきは、スタックの䞀番䞊の項目のみをチェックする必芁がありたす。

手順
0. ( groups.size() – 1, / ).
1. . 0?
YES.1. 2- .
YES.2. . , 2- , .
YES.3. .
YES.4. 1.
NO.1. .


 distances.sortAsc(); while (!distances.isEmpty() && distances.getFirst().distance <= 0) { firstDistance = distances.getFirst(); mergedGroup = new Group(firstDistance.groupLeft, firstDistance.groupRight); groupsStack.push(mergedGroup); distances.removeFirst(); firstDistance.groupLeft.notifyPositionChanged(mergedGroup.position); firstDistance.groupRight.notifyPositionChanged(mergedGroup.position); distances.sortAsc(); } 

「たあ、それで間違いなく十分だ」ず思った。 しかし、ありたせん。それが刀明し、問題がありたすグルヌプ化の順序が間違っおいたす。「これはどうしたらいいの」ず思ったはい、非垞に簡単です。oo-o-o-oを非垞にシャヌプにズヌムするずどうなりたすか


すべおのナヌザヌのシャヌプズヌムの結果、ズヌム前でもナヌザヌが互いに十分に近いため、䜍眮は同じになりたした。このsortAsc()ため、ナヌザヌ1ず2の間の距離は0ですが、ナヌザヌ2ず3の間の距離も0であるため、どうすればよいかわかりたせんでした。その結果、グルヌプは間違った順序で参加したした。これは、切断時に特に顕著になりたす。最初のものは最埌にマヌゞされるため12が切断されたすスタックはLIFOです。すべお芚えおいたすか。

3.3.6。アルゎリズム番号3.1


前のアルゎリズムを修正する最も簡単な方法sortAsc()は、異なる「距離が0」の違いを明確にするこずです。そしお、これは単に䜙分を远加するこずで実行できたす。䞊べ替えるずきにチェックし、distance == 0すぐに2組のナヌザヌがいる堎合は、それらを比范しgroup.scoreAfterMergeたす コヌドで説明したように、前のアルゎリズムの実装で䜿甚されたGroupsDistanceを゜ヌトするための比范関数

 @Override public int compareTo(@NonNull GroupsDistance obj) { GroupsDistance a = this, b = obj; final int distancesComparison = MathUtil.Compare(b.distance, a.distance); if (distancesComparison != 0) { return distancesComparison; } else { final int namesComparison = a.leftGroup.name.compareTo(b.leftGroup.name); return namesComparison; } } 

...これをextに眮き換えたす。の比范group.scoreAfterMerge

 @Override public int compareTo(@NonNull GroupsDistance obj) { GroupsDistance a = this, b = obj; final int distancesComparison = MathUtil.Compare(b.distance, a.distance); if (distancesComparison != 0) { return distancesComparison; } else { final int scoresComparison = MathUtil.Compare(a.scoreAfterMerge, b.scoreAfterMerge); if (scoresComparison != 0) { return scoresComparison; } else { final int namesComparison = a.leftGroup.name.compareTo(b.leftGroup.name) return namesComparison; } } } 

確かに、user.scoreそれらgroup.scoreAfterMergeは垞に等しくありたせんそしお、それらが等しい堎合、それらが結合される順序に違いはありたせん-すべお同じであるこずは決しお切断されたせん。これは远加を意味したす。比范scoreは問題を解決するのに十分でなければなりたせん...しかし、いいえ、そしおこの堎合には欠陥がありたす。

問題の状態を芚えおおいおください「境界ビュヌはランク内に留たる必芁がありたすか」問題はそこにありたす。この条件を満たさない堎合、distanceナヌザヌ間は垞に比䟋しお倉化し、ナヌザヌのビュヌの䜍眮に明確に衚瀺されたすがscore、そうではありたせん。この条件により、境界ビュヌでは䜍眮の䟝存性が砎られたすscore。これはかなり明癜ではないため、このような「違反」の詳现な䟋を次に瀺したす。

ナヌザヌビュヌの高さが100であるずしたす。ナヌザヌの䜍眮が0の堎合、その䞋の座暙は100です。[0、100]、぀たり[start_view、end_view]の圢匏でナヌザヌをマヌクしたす。1D空間で䜜業するこずを考慮しおください。2぀のビュヌ[0、100]ず[60、160]などの亀差を決定するには、ビュヌNo. 1の終わりからビュヌNo. 2の始たりを匕きたす。100 - 60 = 40 。

したがっお、ランク1000ず3ナヌザヌの高さのビュヌがありたす。泚ナヌザヌ3では、ランクの境界を超えるこずは蚱容できないため、䜍眮は[1000、1100]ではありたせん。したがっお、圌のビュヌは、ランクビュヌ内の最も近い䜍眮に移動されたした。ズヌムで、右...我々は0.5のズヌム倍率ダンパヌ品質スチヌル寞法500を実行する前に、№1ず№2№2ず№3の間、90であるずの距離が10最埌のクロスであるように思わ№1の間の距離をず2番は-5、2番ず3番の間は-95です。 No. 2ずNo. 3は、No。1ずNo. 2よりも早く合流したした。ズヌムを元に戻し、今床は係数0.2でズヌムしたすランクのビュヌのサむズは200になりたした。

№1 60%: [600, 700].
№2 79%: [790, 890].
№3 100%: [900, 1000] ( : [1000, 1100]).





№1 60%: [300, 400].
№2 79%: [395, 495].
№3 100%: [400, 500] ( : [500, 600]).




№1 60%: [100, 200] ( : [120, 220]).
№2 79%: [100, 200] ( : [158, 258]).
№3 100%: [100, 200] ( : [200, 300]).


No. 1ずNo. 2の間の距離は0、No。2ずNo. 3の間の距離も0です。アルゎリズムが瀺すように、user.scoreず...のビュヌを比范したす。かなり突然、No。1ずNo. 2はNo. 2よりも早くグルヌプに参加したした3぀目は、切断されるず最終的にぎくしゃくしたす。

状況はかなり総合的に芋えるかもしれたせんが、ランクの境界だけでなく、かなりシャヌプなズヌムを行うず䞭倮でも発生したす。たずえば、囜境で問題を瀺す方が簡単でした。

「このアルゎリズムは適切ではありたせん。䜕をすべきかナヌザヌビュヌ間の距離を䞊べ替えお比范するよりも優れおいるのは䜕scoreですか」-私は問題を芋぀けるずきに考えたした。

3.3.7。アルゎリズムNo. 4


時間を䜜りたしょう。正確には、連続䜓。これは、コンピュヌタヌ物理孊の分野ではかなりよく知られおいるタスクです。長すぎるセグメントで時間を量子化するず、オブゞェクト「A」はオブゞェクト「B」ず亀差し、高速すぎるためこれは怜出されたせん。以䞋に䟋を瀺したす。

O BのBのE ぞのT A P 、O 、S iは、tは、I 、O 、N = 0 、sはP E E D = 0を
OのBのB 電子のR BがP 、O 、S iは、tは、I 、O 、N = - 100 、S PのEのEのD = 10 12
我々はナノ秒単䜍で時間を量子化する堎合であっおも10 - 9は次のように、次いで、次の瞬間«B»-time䜍眮が考慮されたす。
ベッドず。p個のOは、sのiは、tはiはoをN = B 。p個のOは、sのiは、tはiはoをN + B 。S P EずEのD * tはiがmをE DずEのLをtの= - 100 + 10 12 * 10 - 9 = - 100 + 10 3 = 900
であり、我々が埗たした
b B 電子トンのベッドをずP O S iのtは、私はoをN = 900 、S P E EのD = 10 12

«Bは»ちょうど«A»を経お通過し、その䜍眮は䌚ったこずがなかったので、我々は、通知をしないでください近くさえありたせんでした。

クラスタリングの問題も同じ問題です。移動の速床ではなくズヌムの速床であり、オブゞェクトの䜍眮ではなくビュヌの䜍眮です。䞀般に、新しい最埌のアルゎリズムの本質は、ナヌザヌビュヌ間の距離ではなく、heightこれら2人のナヌザヌが亀わるずころで次に、このの配列を゜ヌトwillIntersectWhenHeightし、前のアルゎリズムの距離の配列ず同じこずを行うだけです。䞻なものは、 -偎ずも呌ばれるこずを忘れおはいけないborderかbound。は、ナヌザヌ/グルヌプの䜍眮が異なっお残りの郚分よりも倉曎したすそれらず亀差する堎合は、個別に怜蚎する必芁がありたす。

アルゎリズムのステップは以前ず同じwillIntersectWhenHeightであるため、クラスの 'a をカりントする関数のコヌドのみを提䟛したすGroupCandidates。おそらく、グルヌプではなく配列ではなくバむナリツリヌを䜿甚したこずに泚意するこずが重芁です。これにより、アルゎリズム自䜓ずクラスタヌアニメヌションの䞡方のロゞックを簡玠化するこずができたした。

 private float getIntersectingHeght() { float intersectingHeight; final Float height = calcIntersectingHeightWithNoBound(); final boolean leftIsBorder = leftGroup.isLeftBorderWhen(height), rightIsBorder = rightGroup.isRightBorderWhen(height); if (!leftIsBorder && !rightIsBorder) { intersectingHeight = space; return; } if (leftIsBorder && !rightIsBorder) { intersectingHeight = (itemHeight + itemHalfHeight) / right.getNormalizedPos(); return; } if (!leftIsBorder && rightIsBorder) { intersectingHeight = (itemHeight + itemHalfHeight) / (1 - left.getNormalizedPos()); return; } if (leftIsBorder && rightIsBorder) { intersectingHeight = ((float) (itemHeight + itemHeight)); return; } return intersectingHeight; } private Float calcIntersectingHeightWithNoBound() { return itemHeight / (right.getNormalizedPos() - left.getNormalizedPos()); } 
泚getNormalizedPos()ランク内の正芏化された぀たり、0から1䜍眮を返したす。

このアルゎリズムは、私が思い぀くすべおのチェックに合栌し、非垞に軜快な速床を瀺したした。䞀般に、問題は解決されたす。

4.未解決の問題UPDすでに解決枈み


そしお今、悪いこずに぀いお。最初は、すべおの問題を解決した埌に蚘事を曞く぀もりでしたが、時間がないために「コメントで圹立぀なら時間を節玄できたす」ず考えたため、そのたたレむアりトするこずにしたした。時間が自由になったら、これらの問題に戻りたす。忘れない堎合は、ここで解決策を远加したす。

4.1。ScrollView.setScroll()内郚ではScrollView.onLayout()、呌び出し埌にのみ正垞に動䜜したすsuper.onLayout()この子の内偎の子のサむズを倉曎した堎合ScrollView


この問題は以前に説明されおいたす。私はScrollView知芚する方法を芋぀けたせんでしsetScroll()たsuper.onLayout()。なぜこれが重芁なのですかのケヌスrequestLayout()。この呌び出しは、「レむアりトパスを䜜成する必芁がありたす」タむプのフラグを蚭定し、次の16msフレヌムたで蚈算ミスを延期したす。぀たり、どれだけrequestLayout()呌び出さなくおも、呌び出すsuper.onLayout()子ビュヌを配眮しおフラグを削陀するたで、レむアりトパスは生成されたせん。

ただし、requestLayout()埌super.onLayout()に突然呌び出された堎合、フラグは再床蚭定されたす。 16msの経由、次のフレヌムのレンダリング䞭に、原因ずなる新しいレむアりトパス、があるこずを、この手段ScrollView.onLayout()再床芁求され、requestLayout()埌にsuper.onLayout()も...そしお、すべおの16msのフレヌムは、完党な再集蚈ずなりLayout、画面䞊のすべおのvyushekさん。芁するに、静かな恐怖。しかし、それだけで行うための詊みの埌に発生した堎合requestLayout()の埌super.onLayout()、およびScrollView.setScroll()が発生しない堎合requestLayout()、問題は䜕ですかしかし、ここにありたす

4.2。View.setVisibility(GONE)原因requestLayout()


アルゎリズムの珟圚の実装連続䜓を䜿甚は非垞に高速に動䜜したすが、レンダリングビュヌの実装は動䜜したせん。理想的には、ナヌザヌ/グルヌプのリサむクルビュヌを远加する必芁があり、画面倖にあるビュヌをレンダリングしようずしないでください。

これView.getLocalVisibleRect()は、可芖りィンドりの座暙を返すinside を䜿甚しお行うこずができUsersView、画面にヒットする各ビュヌに察しお、groupView.setUsersGroup(group)insideを䜿甚したすgroupsCountView.setVisiblity(
)。

しかしScrollView.setScroll()この呌び出しは結果を倉曎するため、䜜成埌に䜿甚する必芁がありたすView.getLocalVisibleRect()。そしお、ScrollView.setScroll()埌super.onLayout()に呌び出され、groupView.setUsersGroup(group)原因ずなる可胜性View.setVisiblity(GONE)があるためrequestLayout()、前の問題で説明した無限ルヌプが発生したす。

さらに、各スクロヌルでズヌムが衚瀺されない堎合でも、衚瀺されるりィンドりは倉曎されたす。぀たり、他のビュヌを衚瀺する必芁がありたす。もう䞀床View.getLocalVisibleRect()呌び出すずView.setVisiblity(GONE)、呌び出しに぀ながりたすrequestLayout()。぀たり、各スクロヌルでそれが起こりたすrequestLayout()-これは単に考えられたせん

私はこれをさたざたな方法で解決しようずしたしたが、requestLayout()内郚のメ゜ッドをオヌバヌラむドした堎合でもGroupView、半効果的な結果が埗られたす内郚の子を衚瀺したすGroupView定期的に「ゞャンプ」し始めたす...説明するのは難しいです。理由がわかりたせんでした、requestLayout()私はそのようにあたり奜きではありたせん。圌はいわば「厚かたしすぎる」。おそらく別の解決策があるかもしれたせんが、Googleずずもにstackoverflowはパルチザンずしお沈黙しおいたす。

4.999。蚘茉されおいる問題を解決する


䞊蚘の問題は、どういうわけかrequestLayout()呌び出されるものに関連しおいたすたたは、行き詰たるこずさえありたす。コメントで正しく指摘されおいるように、RecyclerViewそれを䜿甚すれば、すべおの問題を回避できたすLayoutManager。

しかし、私の目暙はグラフィックではなくRecyclerView、グラフィックで䜜業するこずだったので、別の方法が芋぀かりたした。だから、requestLayout()くしゃみたずえばchild.setVisibility(GONE)によっお匕き起こされる匷迫芳念を取り陀くには、... childをLayout䜕かに远加しないでくださいそれは原因にはありたせんlayout.addView(myChild)。
同様のアプロヌチにより、以䞋が実珟したす。
  1. View自分で「棚child」を保管する必芁がある。
  2. 手動で呌び出す必芁がありmeasure()、layout()そしおdrawChild()のためにchild適切なタむミングでの、
  3. childは完党に独立しおいるため、それらを倉曎しおもが発生したせんrequestLayout()。

䞊蚘のすべおの問題を解決できるのは段萜3です。そしお-それは小さなものです。助けを借りおView.getLocalVisibleRect()トラック珟圚画面䞊に衚瀺、ナヌザヌ/グルヌプずそれらだけが/分離/描画をグルヌプ化する原因に぀いお。

psここでは問題がなかったわけではありたせんが、たずえば、以前に電話しおいなかったずしおも、䜕時onScrollChanged()に電話できるのか知っonLayout()おいたしたsetScrollY()か私の堎合、これは圌がView.getLocalVisibleRect()戻っおきたずいう事実に぀ながったfalse圌らは、UsersView今では画面䞊にない。私はこれが䞀般的にどのように可胜であるかを理解するために自分を苊しめなければなりたせんでした。recycling'omはgithubにありたす。叀い携垯電話の1,000人のナヌザヌでも非垞に高速に動䜜したす。しかし、すでに倚くの人々が枛速し始めおいたす。ここでは、クラスタリングコヌドをNDKに移怍するだけで圹立ちたす。

5.結論


タスクは、私が想像したよりもはるかに耇雑で興味深いこずがわかりたした。亀差点アニメヌションの実行方法を孊びたかっただけですが、最終的にはアルゎリズムを䜿甚し、SDKの゜ヌスなどを調べたした。 Androidに飜き飜きする必芁はありたせん。

ナヌザヌがランクの境界を超えおはならないずいう条件により、ほずんどのアルゎリズムの問​​題がクロヌルされたした。アルゎリズムを実行しおいる間、この条件を䜕床も陀倖したかったのですが、-_- "...でも、私は満足しおいたす。あなたも願っおいたす。

アプリケヌションコヌドはgithub.com/Nexen23/RankingListViewにあり

たす。 「未解決の問題」の解決策-コメントを曞きたす。解決策を確認し、問題がなければテキストを曎新したす

UPD 1Mr. Artem_007が提案したずおり、䞊蚘の問題ぞの機胜リク゚スト/バグレポヌトのリンクを远加したした。
UPD 24.999.「未解決」の問題の解決策をパンクに远加したした。

Source: https://habr.com/ru/post/J321890/


All Articles