This article has been authorized to be reprinted by guolin_blog, an official wechat account.
The control makes it easy to debug the response data, as shown below:
Control styles refer to the following website:
JSON online parsing and formatting verification
Project GitHub: JSONRecyclerView
Project Demo GitHub: JSONRecyclerViewDemo
An overview of the
Control is based on RecyclerView, the text will present the corresponding color to reflect the corresponding type, if the value type is JSONObject or JSONArray, the corresponding view of the data can be expanded or contracted, in addition, the size or color of the text can be customized change.
Texts are divided into the following seven types:
- Common text: colon, curly braces, curly braces, comma, Object{… } and Array [].
- Text of type key
- String text
- Text of type Number
- Boolean text
- The url text
- Null text
The default text color is as follows:
<color name="default_text_color"># 333333</color>
<color name="default_key_color">#92278f</color>
<color name="default_string_color">#3ab54a</color>
<color name="default_number_color">#25aae2</color>
<color name="default_boolean_color">#f98280</color>
<color name="default_url_color">#61d2d6</color>
<color name="default_null_color">#f1592a</color>
Copy the code
Method of use
The usage method is as follows:
Import to project
Add the following code to the build.gradle file of the main project:
allprojects {
repositories {
...
maven { url 'https://jitpack.io'}}}Copy the code
Then add the dependency to the module you want to use. The corresponding build.gradle file code looks like this:
dependencies {
implementation 'com. Making. TanJiaJunBeyond: JSONRecyclerView: 1.0.0'
}
Copy the code
Add to view
Then add JsonRecyclerView to the XML file as follows:
<com.tanjiajun.jsonrecyclerview.view.JSONRecyclerView
android:id="@+id/rv_json"
android:layout_width="match_parent"
android:layout_height="match_parent" />
Copy the code
Or add it to the view using the addView related method as follows:
val rvJson = JSONRecyclerView(this)
linearLayout.addView(rvJson)
Copy the code
We can change the style using the setStyle method as follows:
rvJson.setStyles(textColor = ContextCompat.getColor(this,R.color.black))
Copy the code
Data binding
BindData using the bindData method, which accepts JSON string, JSONObject, and JSONArray data.
When our data type is JSON string, we can call the following methods:
// JSONRecyclerView.kt
/** * Bind JSON string data. * Bind the json string data. * *@paramJsonString The JSON string to bind. * /
fun bindData(jsonString: String) =
adapter.bindData(jsonString)
Copy the code
When our data type is JSONObject, we can call the following methods:
// JSONRecyclerView.kt
/** * bind JSONObject data. * Bind the json object data. * *@paramJsonObject The JSON object to bind. * /
fun bindData(jsonObject: JSONObject) =
adapter.bindData(jsonObject)
Copy the code
When our data type is JSONArray, we can call the following methods:
// JSONRecyclerView.kt
/** * Bind JSONArray data. * Bind the json array data. * *@paramJsonArray The JSON array to bind. * /
fun bindData(jsonArray: JSONArray) =
adapter.bindData(jsonArray)
Copy the code
The sample code
The code looks like this:
package com.tanjiajun.jsonrecyclerviewdemo
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.tanjiajun.jsonrecyclerview.view.JSONRecyclerView
/** * Created by TanJiaJun on 6/1/21. */
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<JSONRecyclerView>(R.id.rv_json).bindData(
"{\n" +
" \"string\":\"string\",\n" +
" \"number\":100,\n" +
" \"boolean\":true,\n" +
" \"url\":\"https://github.com/TanJiaJunBeyond/JSONRecyclerView\",\n" +
" \"JSONObject\":{\n" +
" \"string\":\"string\",\n" +
" \"number\":100,\n" +
" \"boolean\":true\n" +
" },\n" +
" \"JSONArray\":[\n" +
" {\n" +
" \"string\":\"string\",\n" +
" \"number\":100,\n" +
" \"boolean\":true\n" +
" }\n" +
" ]\n" +
"}")}}Copy the code
The core code
Most of the codes have corresponding annotations in Both Chinese and English, maybe some translation is not good, please forgive me.
As mentioned above, the control is based onRecyclerView, involving JsonItemView, JsonViewAdapter and JsonRecyclerView three classes.
JSONItemView
The layout file is Item_jSON_view.xml. This class inherits the LinearLayout with four key variables, as shown below:
// JSONItemView.kt
private lateinit var tvLeft: TextView
private lateinit var ivIcon: ImageView
private lateinit var tvRight: TextView
/** * Set the scaled Pixel text size. * /
var textSize = DEFAULT_TEXT_SIZE_SP
set(value) {
// Range is [12.0f, 30.0f]
field = when {
value < 12.0 F -> 12.0 F
value > 30.0 F -> 30.0 F
else -> value
}
// Set the text size of the text on the left
tvLeft.textSize = field
// Set the size of the display expand and shrink ICONS
val size = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
field,
resources.displayMetrics
).toInt()
ivIcon.layoutParams = (ivIcon.layoutParams as LinearLayout.LayoutParams).apply {
width = size
height = size
}
// Set the text size of the text on the right
tvRight.textSize = field
}
Copy the code
-
The variable tvLeft is the TextView on the left that displays the key-related text.
-
The variable ivIcon is the ImageView in the middle, used to display the expanded or contracted icon
-
The variable tvRight is the TextView on the right that displays the text associated with value.
-
TextSize is a public variable that can be used to change the size of the text. Note that the unit is sp. The minimum value of the text is 12sp and the maximum value is 30sp.
JSONViewAdapter
This class is used to process different types of data and click related logic, it inherits RecyclerView.Adapter, mainly involves the following key methods:
OnBindViewHolder method
The code looks like this:
// JSONViewAdapter.kt
override fun onBindViewHolder(holder: JSONViewAdapter.JsonItemViewHolder, position: Int) {
with(holder.jsonItemView) {
textSize = this@JSONViewAdapter.textSize setRightColor(textColor) jsonObject? .let { bindJSONObjectData(position, it) } jsonArray? .let { bindJSONArrayData(position, it) } } }Copy the code
It binds data to the view, calling the bindJSONObjectData method if the data type is JSONObject or the bindJSONArrayData method if the data type is JSONArray.
HandleValue method
The code looks like this:
// JSONViewAdapter.kt
/** * Handle the styling of the right part of the json item view (i.e., The part that shows the value). * Handles the style of the right part of the JsonItemView (that is, the part that shows the value). * *@paramImage The image to be displayed in The JSON item view. *@paramThe json Item view to be processed. *@paramAppendComma Whether to append commas. *@paramHierarchy The number of views hierarchies. * /
private fun handleValue(
value: Any? , itemView:JSONItemView,
appendComma: Boolean,
hierarchy: Int
) {
itemView.showRight(SpannableStringBuilder().apply {
when (value) {
is Number ->
// Handle styles with values of type Number
handleNumberValue(itemView, value)
is Boolean ->
// Handle styles with Boolean values
handleBooleanValue(itemView, value)
is String ->
// Handle styles with a String value
handleStringValue(itemView, value)
is JSONObject ->
// Handle styles with values of type JSONObject
handleJSONObjectValue(itemView, value, appendComma, hierarchy)
is JSONArray ->
// Handle styles with values of type JSONArray
handleJSONArrayValue(itemView, value, appendComma, hierarchy)
else ->
// Handle the null style
handleNullValue(itemView)
}
if (appendComma) append(",")})}Copy the code
OnClick method
If the data type is JSONObject or JSONArray, you can click to expand or shrink the view as follows:
The performFirstExpand method is called if it is the first expansion, otherwise the performClick method is called as follows:
// JSONViewAdapter.kt
override fun onClick(v: View?). {
// If itemView has 1 child views, this is the first expansion
(itemView.childCount == 1)
.yes { performFirstExpand() }
.otherwise { performClick() }
}
Copy the code
PerformFirstExpand method
This method is used to expand the corresponding itemView of JSONObject or JSONArray for the first time. The code is as follows:
// JSONViewAdapter.kt
/** * The first time the view corresponding to a JSONObject or JSONArray is expanded. * Expand the itemView corresponding to the JSONObject or JSONArray for the first time. * /
private fun performFirstExpand(a) {
isExpanded = true
itemView.showIcon(false)
itemView.tag = itemView.getRightText()
itemView.showRight(if (isJsonObject) "{" else "[")
// Expand the view below that level
val array: JSONArray? =
if (isJsonObject) (value as JSONObject).names() else value as JSONArray
vallength = array? .length() ? :0
for (i in 0 until length) {
itemView.addViewNoInvalidate(JSONItemView(itemView.context).apply {
textSize = this@JSONViewAdapter.textSize
setRightColor(textColor)
valchildValue = array? .opt(i) isJsonObject .yes { handleJSONObject( key = childValueas String,
value = (value as JSONObject)[childValue],
appendComma = i < length - 1,
hierarchy = hierarchy
)
}
.otherwise {
handleJSONArray(
value = childValue,
appendComma = i < length - 1,
hierarchy = hierarchy
)
}
})
}
// Displays the last view of the hierarchy
itemView.addViewNoInvalidate(JSONItemView(itemView.context).apply {
textSize = this@JSONViewAdapter.textSize
setRightColor(textColor)
showRight(
StringBuilder(getHierarchyStr(hierarchy - 1))
.append(if (isJsonObject) "}" else "]")
.append(if (appendComma) "," else ""))})/ / redraw itemView
itemView.requestLayout()
itemView.invalidate()
}
Copy the code
PerformClick method
This method is used to expand or shrink when clicked, as shown below:
/** * Click to expand or collapse. * /
private fun performClick(a) {
itemView.showIcon(isExpanded)
val rightText = itemView.getRightText()
itemView.showRight(itemView.tag as CharSequence)
itemView.tag = rightText
for (i in 1 until itemView.childCount) {
// Make all child views visible if expanded, hidden otherwise
itemView.getChildAt(i).visibility = if (isExpanded) View.GONE elseView.VISIBLE } isExpanded = ! isExpanded }Copy the code
If the data type is url, you can click to open the browser and view it as follows:
/** * Click to expand or collapse. * /
private fun performClick(a) {
itemView.showIcon(isExpanded)
val rightText = itemView.getRightText()
itemView.showRight(itemView.tag as CharSequence)
itemView.tag = rightText
for (i in 1 until itemView.childCount) {
// Make all child views visible if expanded, hidden otherwise
itemView.getChildAt(i).visibility = if (isExpanded) View.GONE elseView.VISIBLE } isExpanded = ! isExpanded }Copy the code
The regular expression to determine whether it is a URL type is as follows, and the comments are quite detailed, so I won’t repeat them here:
private val urlPattern: Pattern = Pattern.compile(
/ / verification is http://, https://, ftp://, RTSP: / /, mms://, one of them
"^((http|https|ftp|rtsp|mms)? : / /)?" +
// Check whether the character is an FTP address (ftp://user:password@)
// Check whether the characters are 0 to 9, lowercase letters a to z, _,! , ~, *, ', (,), period (.), &, =, +, $, %, - One of them can be matched zero times or once
"(([0-9a-z_!~*'().&=+\$%-]+: )?" +
// Check whether the characters are 0 to 9, lowercase letters a to z, _,! , ~, *, ', (,), period (.), &, =, +, $, %, - One of them can be matched once or more
"[0-9a-z_!~*'().&=+\$%-]+" +
/ / @
"@)?" +
// Check whether the character is an IP address, for example, 192.168.255.255
// Determine if the character matches 1+[0 to 9, twice], for example, 192
"((1\\d{2}" +
/ / or
"|" +
// Check whether the character matches 2+[0 to 4, once]+[0 to 9, once], for example, 225
"2[0-4]\\d" +
/ / or
"|" +
// Determine if the character matches 25+[0 to 5, once], for example, 255
"25 [0 to 5]" +
/ / or
"|" +
// Check whether the character matches [1 to 9, once]+[0 to 9, once], for example, 25
"[1-9]\\d" +
/ / or
"|" +
// Determine if the character matches 1 to 9 once, for example, 5
"[1-9])" +
Matching \. / / whether characters (1 \ d {2} | \ [0-4] 2 d 25 [0 to 5) | | \ | d \ [1-9] d), matching three times
"(\\.(" +
// Determine if the character matches 1+[0 to 9, twice], for example, 192
"1\\d{2}" +
/ / or
"|" +
// Check whether the character matches 2+[0 to 4, once]+[0 to 9, once], for example, 225
"2[0-4]\\d" +
/ / or
"|" +
// Determine if the character matches 25+[0 to 5, once], for example, 255
"25 [0 to 5]" +
/ / or
"|" +
// Check whether characters match [1 to 9]+[0 to 9], for example, 25
"[1-9]\\d" +
/ / or
"|" +
// Determine if the character matches 0 to 9 once, for example, 5
"\\d))" +
// Match three times
"{3}" +
/ / or
"|" +
// Check whether the character is a Domain Name.
// Level 3 domain name or higher, check whether the characters are 0 to 9, lowercase letters a to Z, _, and! , ~, *, ', (,), - One of them matches zero or more times, and then adds., for example, WWW.
"([0-9a-z_!~*'()-]+\\.) *" +
The second character is 0 to 9, lowercase letters A to Z, and -. The second character is 0 to 9, lowercase letters A to Z, and -. The second character can be matched at most 61 times. Finally determine if the third character is one of the lowercase letters a to Z and 0 to 9.
"([0-9 a-z] [0-9 a-z -], 21 {0})? [0-9a-z]" +
// The top-level domain name is matched at least twice and at most six times, for example,.com and.cn
"\ \. [a-z] {2, 6})" +
+[0 to 9, at least once and at most four times], zero times or once
"(: [0-9] {1, 4})?" +
// Determines whether the character is a slash (/), matching zero times or once. If there is no filename, no slash is required
"((/?)|" +
// Check whether the characters are 0 to 9, lowercase letters a to z, uppercase letters a to z, _,! , ~, *, ', (,),. ,? , :, @, &, =, +, $,, %, #, - One of them can be matched once or more
"(/[0-9a-zA-Z_!~*'(){}.;?:@&=+\$,%#-]+)+" +
// Check whether the character is a slash (/), matching zero times or once
"/? \ $"
)
Copy the code
The regular expression visualization is as follows:
JSONRecyclerView
This class is used to present the data to the view as a list, annotated so clearly that I won’t repeat it here. The code looks like this:
// JSONRecyclerView.kt
package com.tanjiajun.jsonrecyclerview.view
import android.content.Context
import android.util.AttributeSet
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tanjiajun.jsonrecyclerview.DEFAULT_TEXT_SIZE_SP
import com.tanjiajun.jsonrecyclerview.R
import com.tanjiajun.jsonrecyclerview.adapter.JSONViewAdapter
import org.json.JSONArray
import org.json.JSONObject
/** * Created by TanJiaJun on 5/31/21. */
class JSONRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
private val adapter = JSONViewAdapter(context)
init {
layoutManager = LinearLayoutManager(context)
setAdapter(adapter)
}
/** * Bind JSON string data. * Bind the json string data. * *@paramJsonString The JSON string to bind. * /
fun bindData(jsonString: String) =
adapter.bindData(jsonString)
/** * bind JSONObject data. * Bind the json object data. * *@paramJsonObject The JSON object to bind. * /
fun bindData(jsonObject: JSONObject) =
adapter.bindData(jsonObject)
/** * Bind JSONArray data. * Bind the json array data. * *@paramJsonArray The JSON array to bind. * /
fun bindData(jsonArray: JSONArray) =
adapter.bindData(jsonArray)
/** * Sets the style of JsonItemView. * Set the json item view styles. * *@paramTextSize The size of all text. *@paramTextColor The normal text color. (Normal text color) *@paramKeyColor The color of The text of type key. *@paramStringColor The color of The text of type String. *@paramNumberColor The color of The text of type Number. *@paramBooleanColor The color of text of type Boolean. *@paramUrlColor The color of The URL text. *@paramNullColor The color of null text. * /
@JvmOverloads
fun setStyles(
textSize: Float = DEFAULT_TEXT_SIZE_SP,
@ColorInt textColor: Int = ContextCompat.getColor(context, R.color.default_text_color).@ColorInt keyColor: Int = ContextCompat.getColor(context, R.color.default_key_color),
@ColorInt stringColor: Int = ContextCompat.getColor(context, R.color.default_string_color),
@ColorInt numberColor: Int = ContextCompat.getColor(context, R.color.default_number_color),
@ColorInt booleanColor: Int = ContextCompat.getColor(
context,
R.color.default_boolean_color
),
@ColorInt urlColor: Int = ContextCompat.getColor(context, R.color.default_url_color),
@ColorInt nullColor: Int = ContextCompat.getColor(context, R.color.default_null_color)
) {
with(adapter) {
this.textSize = when {
textSize < MIN_TEXT_SIZE -> MIN_TEXT_SIZE
textSize > MAX_TEXT_SIZE -> MAX_TEXT_SIZE
else -> textSize
}
this.textColor = textColor
this.keyColor = keyColor
this.stringColor = stringColor
this.numberColor = numberColor
this.booleanColor = booleanColor
this.urlColor = urlColor
this.nullColor = nullColor
// Refresh the list
notifyDataSetChanged()
}
}
private companion object {
const val MIN_TEXT_SIZE = 12.0 F
const val MAX_TEXT_SIZE = 24.0 F}}Copy the code
digression
A web site that visualizes regular expressions is as follows:
Regexper
My GitHub: TanJiaJunBeyond
Common Android Framework: Common Android framework
My nuggets: Tan Jiajun
My simple book: Tan Jiajun
My CSDN: Tan Jiajun