記事のディレクトリ
最初のレンダリング
序文
友人が数日前に私に、ルールに完全に準拠しているが頭痛の種であるJson解析に基づいてツリーのようなリストを実装する方法を尋ねました。以下の形式を参照してください。一部のAndroid開発者にとって、このJsonはおそらく友好的ではありません。 、それをエンティティクラスに直接変換する方法はありません。実際、このJson解析の文字列を折りたたみ可能なリストにマッピングすることは難しくありません。
コードはGithubに送信されました:https://github.com/ThirdGoddess/AndroidTree
{
"code":"200",
"message":"success",
"data":[
{
"id":"1001",
"title":"编号1",
"next":[
{
"id":"10011",
"title":"编号1-1"
},
{
"id":"10012",
"title":"编号1-2",
"next":[
{
"id":"100121",
"title":"编号1-2-1",
"next":[
{
"id":"1001211",
"title":"编号1-2-1-1"
},
{
"id":"1001212",
"title":"编号1-2-1-2"
},
{
"id":"1001213",
"title":"编号1-2-1-3"
},
{
"id":"1001214",
"title":"编号1-2-1-4"
},
{
"id":"1001215",
"title":"编号1-2-1-5"
}
]
},
{
"id":"100122",
"title":"编号1-2-2"
},
{
"id":"100123",
"title":"编号1-2-3",
"next":[
{
"id":"1001231",
"title":"编号1-2-3-1"
},
{
"id":"1001232",
"title":"编号1-2-3-2"
},
{
"id":"1001233",
"title":"编号1-2-3-3"
},
{
"id":"1001234",
"title":"编号1-2-3-4"
},
{
"id":"1001235",
"title":"编号1-2-3-5"
}
]
}
]
},
{
"id":"10013",
"title":"编号1-3"
}
]
},
{
"id":"1002",
"title":"编号2"
},
{
"id":"1003",
"title":"编号3"
},
{
"id":"1004",
"title":"编号4",
"next":[
{
"id":"10041",
"title":"编号4-1"
},
{
"id":"10042",
"title":"编号4-2"
}
]
},
{
"id":"1005",
"title":"编号5"
}
]
}
この不確実なレベルのJsonを大量に取得した場合、どう思いますか?分析に何を使用しますか?どのコントロールを使用する必要がありますか?
レイヤーごとのaddViewメソッド
実際、Gsonを直接使用して解析できますが、このエンティティクラスは自分で作成する必要があります。
package com.example.myapplication;
import java.util.List;
public class DataBean {
private String code;
private String message;
private List<Data> data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public List<Data> getData() {
return data;
}
public void setData(List<Data> data) {
this.data = data;
}
public static class Data {
private String id;
private String title;
private List<Data> next;//重点在这里
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public List<Data> getNext() {
return next;
}
public void setNext(List<Data> next) {
this.next = next;
}
}
}
(OpenParam.jsonはjson文字列です)
Gson分析を使用します。
Kotlin:
val dataBean = Gson().fromJson(OpenParam.json, DataBean().javaClass)
Java:
DataBean dataBean = new Gson().fromJson(OpenParam.json, DataBean.class)
解析されたので、再帰を介して徐々にaddView()を実行して、次のフィールドがnullかどうかを判断できます。ただし、再帰を開始する前に、レイアウトを分析する必要があります。
レベルごとにネストする必要があるため、最初にLinearLayoutを作成します。もちろん、このリストはスライド可能であり、ScrollViewは外側のレイヤーにネストできます。アクティビティレイアウトは次のようになります。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:ignore="MissingConstraints">
<LinearLayout
android:id="@+id/treeLayout"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
各アイテムを分析した後、1つはレイアウトのあるアイテム、もう1つはレイアウトのないアイテムの2つのケースがあります。ネストされた状況、つまり次のフィールドがある場合は、次のフィールドでアイテムを使用できます。レイアウト、そしてその逆もまた別です!次に、これら2つのレイアウトは次のとおりです。
レイアウトあり:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/flag"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginLeft="32dp"
android:padding="8dp"
android:src="@mipmap/open" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="40dp"
android:layout_marginTop="1dp"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingRight="32dp"
android:textColor="#333333" />
</LinearLayout>
<LinearLayout
android:id="@+id/nextLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="32dp"
android:orientation="vertical" />
</LinearLayout>
レイアウトなし:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/info"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="72dp"
android:layout_marginRight="32dp"
android:gravity="center_vertical"
android:textColor="#333333" />
</LinearLayout>
その後、エンティティクラスに従って再帰的に実装され、ループして次のフィールドがあるかどうかを判断し、37行目と69行目の間のコードなどの2つのケースを作成します。既存の子ノードは子レイアウトのアイテムを使用しますが、それ以外の場合は別のアイテムを使用します。
package com.example.myapplication
import android.animation.ObjectAnimator
import android.os.Bundle
import android.view.LayoutInflater.from
import android.view.View
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isGone
import com.google.gson.Gson
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.item_text.view.*
import kotlinx.android.synthetic.main.item_tree.view.*
class MainActivity : AppCompatActivity() {
lateinit var objectAnimator: ObjectAnimator
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//解析Json
val dataBean = Gson().fromJson(OpenParam.json, DataBean().javaClass)
//创建View
createView(dataBean.data, treeLayout)
}
/**
* 递归创建布局
*/
private fun createView(dataList: MutableList<DataBean.Data>, linearLayout: LinearLayout) {
for (i in 0 until dataList.size) {
val title = dataList[i].title
val next = dataList[i].next
if (null != next) {
val childLayout = from(this).inflate(R.layout.item_tree, null, false)
childLayout.title.text = title
//展开和关闭的点击事件
childLayout.title.setOnClickListener {
if (childLayout.nextLayout.isGone) {
//展开
childLayout.nextLayout.visibility = View.VISIBLE
//添点展开动画
objectAnimator = ObjectAnimator.ofFloat(childLayout.flag, "rotation", 0f)
objectAnimator.duration = 400
objectAnimator.start()
} else {
//隐藏
childLayout.nextLayout.visibility = View.GONE
//添点关闭动画
objectAnimator = ObjectAnimator.ofFloat(childLayout.flag, "rotation", -90f)
objectAnimator.duration = 400
objectAnimator.start()
}
}
createView(next, childLayout.nextLayout)
linearLayout.addView(childLayout)
} else {
val textLayout = from(this).inflate(R.layout.item_text, null, false)
textLayout.info.text = title
linearLayout.addView(textLayout)
}
}
}
}
これは達成されます。これは従来の折りたたみリストに適しています。ロードする必要のある状況がさらに発生した場合は、ScrollViewが一番下までスクロールしたかどうか、最後のネットワークロードが完了したかどうかを直接判断できます。条件は次のとおりです。到達したら、27行目をもう一度呼び出します。コードを挿入するだけです。ここではこれ以上の説明はありません。理解できない友達はコメント欄で直接私に尋ねることができます!