ラベルリスト選択view:ChooseFlowView
ラベルリスト選択view:ChooseFlowView
ソースgithub管理アドレスに移行
主に不規則な
一、導入使用
本当はもう1つ記事を書いて紹介しようと思っていたのですが、アクセスは比較的簡単で、そのまま
1.1導入
ルートディレクトリ
プロジェクト
1.2使用
1.2.1定義データモデル
プレゼンテーションなので、データモデルを簡単に定義しました
1.2.2 activityでの使用
次に、
1.2.3コールバック結果の取得
二、設計原理
一般的な話では、汎用クラスのものを書くには、修正に対して閉鎖し、拡張に開放する必要があります.また、ユーザーのアクセスコストは小さくなければなりません.デフォルトの実装があるほうがいいですが、ユーザーの詳細ごとの修正をサポートする必要があります.カスタマイズすることができます.
2.1需要概要
まず、リストの は選択できません.リストの最大および最小選択数は、最大数を超えると を更新する.の3つの状態の が必要である.データの塗りつぶしおよびスタイルのカスタマイズ リスト更新時再利用リスト(イントラチューニングでしょう) 2.2設計思想
以上の需要分析を通じて、この
2.2.1まずITEMの抽象を見る
2.2.2データインタフェースの定義を見る
2.2.3次はChooseFlowViewが提供する機能です
三、実現
当時は
3.1 viewカスタマイズ
まず
ユーザーがカスタム
3.2 viewの更新
3.3操作
ここは文章の重点であり、ユーザーが初めてデータを埋め込んでユーザーインタフェースを初期化する前にユーザーが選択できる最大数と最小数を確定したのは、なぜかというと、ユーザーはデータの山に来る可能性があるが、中の選択状態が最大値を超える場合、コントロールが を解決する.以上のデータのフィルタリングが完了するとページが初期化する、このときページはユーザの要求に従って表示され、このとき取得する結果は信頼性が高く、要求に合致する である.ユーザーのクリック操作に関わる場合、複数選択、単一選択、逆選択が必要な場合は最大数、最小数を設定して**を制御することができる(PS:後に逆選択をサポートするかどうかを追加することができるが、意味が一時的に保留されていないような気がする)** は に加える必要がある.
3.4コアコード
3.4.1初期化データ
3.4.2データの更新
ソースgithub管理アドレスに移行
主に不規則な
ITEM TAG
ラベルのフローLIST
レイアウトに対して、規則的であればRecyclerview
で完全に適任であり、メモリ管理も良好であるが、不規則なものは自分で書く必要がある.文章が長いかもしれないので、ここで効果図を置いて、話す前に大体の理解がある.一、導入使用
本当はもう1つ記事を書いて紹介しようと思っていたのですが、アクセスは比較的簡単で、そのまま
1.1導入
ルートディレクトリ
build.gradle
maven {
url "https://dl.bintray.com/fanyafeng/ripple"
}
プロジェクト
module
のbuild.gradle
implementation 'com.ripple.component:ui:0.0.6'
1.2使用
1.2.1定義データモデル
プレゼンテーションなので、データモデルを簡単に定義しました
data class ChooseModel(var title: String, var checkable: Boolean, var checked: Boolean) :
IChooseModel {
override fun getChooseItemTitle(): String {
return title
}
override fun getChooseItemCheckable(): Boolean {
return checkable
}
override fun getChooseItemChecked(): Boolean {
return checked
}
override fun setChooseItemChecked(isChecked: Boolean) {
checked = isChecked
}
}
1.2.2 activityでの使用
次に、
adapter
にデータを設定する操作を行います.5.forEach {
val model = ChooseModel(" $it", it != 3, it == 0)
list.add(model)
val itemView = ChooseItemView(this)
itemView.setInnerTagWrapContent()
itemView.chooseViewUnselected = R.drawable.choose_view_normal
chooseItemView.addItemView(itemView, model)
}
1.2.3コールバック結果の取得
chooseItemView.onItemClickListener={ first, position, third, fourth, fifth ->
// ,
Log.d(TAG, " :" + position)
}
chooseItemView.onItemAbleClickListener = { view, position, model ->
Log.d(TAG, " :" + position)
showToast(" :" + position)
}
chooseItemView.onItemUnableClickListener = { view, position, model ->
Log.d(TAG, " :" + position)
showToast(" :" + position)
}
二、設計原理
一般的な話では、汎用クラスのものを書くには、修正に対して閉鎖し、拡張に開放する必要があります.また、ユーザーのアクセスコストは小さくなければなりません.デフォルトの実装があるほうがいいですが、ユーザーの詳細ごとの修正をサポートする必要があります.カスタマイズすることができます.
2.1需要概要
まず、
gif
図は3つの部分に分けられ、第1部分はリスト選択コントロールのように勝手にviewを追加し、第2はここで言うポイントChooseFlowView
、第3はレイアウトの修正とコールバックの結果の下で詳しくChooseFLowView
、ここは皆さんがよく知っているある宝あるいはある東商品の詳細ページの多規格選択のview
です.需要は彼らの需要に従って来て、このように需要は需要表を確定しました:ITEM
には、選択、非選択の3つのステータスがあります.FIFO
アルゴリズムに従って選択リストITEM
コールバックをクリックするには、リスニング結果以上の需要分析を通じて、この
ChooseFlowView
の骨格図を列挙することができて、共通のview
をするので、ここはやはりいつものように**インタフェースと汎用**を採用して具体的な実現を行います2.2.1まずITEMの抽象を見る
/**
* Author: fanyafeng
* Data: 2020/6/28 19:24
* Email: [email protected]
* Description: view
*/
interface IChooseItemView:Serializable {
/**
*
*/
fun isCheckable(): Boolean
/**
*
*/
fun setCheckable(isCheckable: Boolean)
/**
*
*/
fun isChecked(): Boolean
/**
*
*/
fun setChecked(isChecked: Boolean)
/**
* Change the checked state of the view to the inverse of its current state
*/
fun toggle()
}
2.2.2データインタフェースの定義を見る
/**
* Author: fanyafeng
* Data: 2020/6/29 09:31
* Email: [email protected]
* Description: item
*
* data model
*/
interface IChooseModel : Serializable {
/**
* view
*/
fun getChooseItemTitle(): String
/**
*
*/
fun getChooseItemCheckable(): Boolean
/**
*
*/
fun getChooseItemChecked(): Boolean
/**
* FIFO data model
*/
fun setChooseItemChecked(isChecked: Boolean)
}
2.2.3次はChooseFlowViewが提供する機能です
/**
* Author: fanyafeng
* Data: 2020/6/29 09:53
* Email: [email protected]
* Description:
*
*/
interface IChooseFlowView : Serializable {
/**
*
*/
fun setMaxChooseCount(maxCount: Int)
/**
* , 1
*/
fun getMaxChooseCount(): Int
/**
*
*/
fun getMinChooseCount(): Int
/**
*
* 0, ,
*/
fun setMinChooseCount(minCount: Int)
}
三、実現
当時は
ChooseFlowView
のカスタマイズについていろいろ考えていましたが、良い実現方法が思いつかず、後に書きながら変更し、最後に比較的良い案を選びました3.1 viewカスタマイズ
まず
tag view
です.これはデフォルトの実装がありますが、デフォルトの実装はIChooseItemView
インタフェースを実装しています.動作を統一するため、このインタフェースを実装する必要があります.また、ChooseFlowView
にITEM
を設定する場合も、このインタフェースを実装する必要があります.さらにdata model
は、データ型の抽象です.ここでは抽象的です.まず、方法の定義を大きく見てみましょう.fun addItemView(
itemView: T,
model: M,
params: LayoutParams? = null
)
ユーザーがカスタム
view
を追加することをサポートしますが、model
もIChooseModel
を実現します.3.2 viewの更新
ChooseFlowView
を更新するには簡単で乱暴な方法があります.すべてのITEM
をやめてから新しく追加することですが、これはよくありません.ここではRecyclerview ViewHolder
の案を真似することができます.ある場合は持ってきてから更新します.役に立たない場合は削除しますが、再利用の問題はやはり前にリセットする必要があります.ここでは覚えておいてください.3.3操作
ここは文章の重点であり、
ChooseFlowView
で実現されたコアコードが最も多い場所でもある.FIFO
(ユーザーの選択習慣に合致する)に従ってフィルタリングする必要があるからだ.同様にユーザがデータを更新することにおいても同様の問題が発生し、これによりデータの表示はChooseFlowView
を更新し、ページを更新するときに選択したデータを再フィルタリングします.ここでは3つのケースがあります.新しいデータが大きい、等しい、小さいなら古いデータより小さい、等しいなら一番いい処理です.data list
を更新してページを更新するだけでいいです.小さいなら余分なview
をremove
と同時にページを更新する必要があります.それより大きい場合はITEM
を新築してChooseFlowView
の3.4コアコード
3.4.1初期化データ
/**
*
*
*/
@JvmOverloads
fun addItemView(
itemView: T,
model: M,
params: LayoutParams? = null
) {
position++
allModelList.add(model)
itemView.initData(model)
itemView.tag = position
val initCount = selectList.size
if (model.getChooseItemChecked()) {
if (initCount >= maxCount) {
val first = selectList.first
(getChildAt(first) as ChooseItemView).toggle()
setItemCheckStatus(selectList.first,false)
selectList.removeFirst()
selectList.addLast(position)
setItemCheckStatus(position,true)
} else {
selectList.addLast(position)
}
}
itemView.setOnClickListener {
val pos = it.tag as Int
val isCheckable: Boolean
/**
*
* ,
*/
var checkRepeat = true
if (itemView.isCheckable()) {
isCheckable = true
val mCount = selectList.size
if (itemView.isChecked()) {
//
if (mCount <= minCount) {
//
checkRepeat = false
} else {
selectList.remove(pos)
setItemCheckStatus(pos,false)
itemView.toggle()
}
} else {
if (mCount >= maxCount) {
//
val first = selectList.first
(getChildAt(first) as ChooseItemView).toggle()
itemView.toggle()
setItemCheckStatus(selectList.first,false)
selectList.removeFirst()
selectList.addLast(pos)
setItemCheckStatus(pos,true)
} else {
//
itemView.toggle()
selectList.addLast(pos)
setItemCheckStatus(pos,true)
}
}
onItemAbleClickListener?.invoke(it, pos, model)
} else {
isCheckable = false
onItemUnableClickListener?.invoke(it, pos, model)
}
onItemClickListener?.invoke(it, pos, model, isCheckable, checkRepeat)
}
if (params != null) {
addView(itemView, params)
} else {
addView(itemView)
}
}
3.4.2データの更新
/**
* view
* view
* view
*/
fun updateView(list: List>) {
selectList.clear()
val newCount = list.size
val oldCount = allModelList.size
if (newCount == oldCount) {
list.forEachIndexed { index, model ->
val chooseModel = model.first
updateSelectList(index, chooseModel)
// model
allModelList[index] = chooseModel
// view
(getChildAt(index) as ChooseItemView).initData(chooseModel)
}
} else if (newCount > oldCount) {
list.forEachIndexed { index, model ->
val chooseModel = model.first
updateSelectList(index, chooseModel)
//
if (index < oldCount) {
allModelList[index] = chooseModel
(getChildAt(index) as ChooseItemView).initData(chooseModel)
} else {
addItemView(model.second, chooseModel)
}
}
} else {
list.forEachIndexed { index, model ->
val chooseModel = model.first
updateSelectList(index, chooseModel)
// model
allModelList[index] = chooseModel
// view
(getChildAt(index) as ChooseItemView).initData(chooseModel)
//
setItemCheckStatus(index,true)
}
(newCount until oldCount).forEach {
allModelList.removeAt(it)
removeViewAt(it)
}
}
}
/**
*
* ,
* datamodel,
*
* , FIFO
*
*/
private fun updateSelectList(selectPosition: Int, chooseModel: IChooseModel) {
val initCount = selectList.size
// item
if (chooseModel.getChooseItemChecked()) {
// ,
if (initCount >= maxCount) {
// model
setItemCheckStatus(selectList.first,false)
//
(getChildAt(selectList.first) as ChooseItemView).toggle()
// item
selectList.removeFirst()
// item
//
selectList.addLast(selectPosition)
// item
setItemCheckStatus(selectPosition,true)
} else {
selectList.addLast(selectPosition)
setItemCheckStatus(selectPosition,true)
}
}
}