具有ConstraintLayout的片段onCreateView不遵守ConstraintSet

问题描述 投票:0回答:1

我正在以编程方式构建我的所有UI,而没有使用XML文件。我的主要UI类继承自AppCompatActivity(),并在UI的主要部分使用了一个名为ClientFragment的片段]

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val layout = ConstraintLayout(this)
    layout.id = R.id.constraint_layout_main_activity
    layout.setBackgroundColor(Color.GREEN)
    setContentView(layout)

    if (savedInstanceState == null) {
        supportFragmentManager.beginTransaction()
            .add(R.id.constraint_layout_main_activity, ClientFragment(), "CLIENT_FRAGMENT")
            .commit()
    }
}

}

我有一个名为BaseGridFragment的抽象基础Fragment类,我所有的片段都将实现。 BaseGridFragment包含屏幕上显示的所有小部件。

abstract class BaseGridFragment : Fragment() {
protected lateinit var progressBar: ProgressBar
protected lateinit var swipeRefreshLayout: SwipeRefreshLayout
private lateinit var recyclerView: RecyclerView
protected lateinit var recyclerAdapter: RecyclerAdapter
private lateinit var constraintSet: ConstraintSet
private lateinit var gridLayoutManager: GridLayoutManager
protected lateinit var searchView: SearchView

protected val requestSender = RequestSender()

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    context?.let { context ->
        val layout = ConstraintLayout(context)
        layout.id = R.id.constraint_layout_base_fragment
        layout.setBackgroundColor(Color.BLUE)

        progressBar = ProgressBar(context)
        progressBar.id = R.id.progress_bar_all_loading

        searchView = SearchView(context)
        searchView.id = R.id.search_view_base_fragment
        searchView.queryHint = "Search"
        searchView.isIconifiedByDefault = false

        gridLayoutManager = GridLayoutManager(context, 2)
        recyclerAdapter =
            RecyclerAdapter {
                onItemClicked(it)
            }

        recyclerView = RecyclerView(context)
        recyclerView.id = R.id.recycler_view_all_list_of_items
        recyclerView.adapter = recyclerAdapter
        recyclerView.layoutManager = gridLayoutManager

        swipeRefreshLayout = SwipeRefreshLayout(context)
        swipeRefreshLayout.id = R.id.swipe_refresh_layout_all_item_list_container
        swipeRefreshLayout.addView(recyclerView)
        swipeRefreshLayout.setOnRefreshListener { fetchData() }

        layout.addView(swipeRefreshLayout)
        layout.addView(progressBar)
        layout.addView(searchView)

        constraintSet = ConstraintSet()
        constraintSet.constrainWidth(R.id.search_view_base_fragment, ConstraintSet.PARENT_ID)
        constraintSet.connect(
            R.id.search_view_base_fragment,
            ConstraintSet.LEFT,
            ConstraintSet.PARENT_ID,
            ConstraintSet.LEFT
        )
        constraintSet.connect(
            R.id.search_view_base_fragment,
            ConstraintSet.TOP,
            ConstraintSet.PARENT_ID,
            ConstraintSet.TOP
        )
        constraintSet.connect(
            R.id.search_view_base_fragment,
            ConstraintSet.RIGHT,
            ConstraintSet.PARENT_ID,
            ConstraintSet.RIGHT
        )
        constraintSet.constrainWidth(R.id.search_view_base_fragment, ConstraintSet.PARENT_ID)
        constraintSet.constrainHeight(
            R.id.search_view_base_fragment,
            ConstraintSet.WRAP_CONTENT
        )
        constraintSet.constrainWidth(R.id.progress_bar_all_loading, ConstraintSet.WRAP_CONTENT)
        constraintSet.constrainHeight(R.id.progress_bar_all_loading, ConstraintSet.WRAP_CONTENT)
        constraintSet.centerHorizontally(R.id.progress_bar_all_loading, ConstraintSet.PARENT_ID)
        constraintSet.centerVertically(R.id.progress_bar_all_loading, ConstraintSet.PARENT_ID)

        constraintSet.connect(
            R.id.swipe_refresh_layout_all_item_list_container,
            ConstraintSet.TOP,
            R.id.search_view_base_fragment,
            ConstraintSet.BOTTOM
        )
        constraintSet.constrainWidth(
            R.id.swipe_refresh_layout_all_item_list_container,
            ConstraintSet.WRAP_CONTENT
        )
        constraintSet.connect(
            R.id.swipe_refresh_layout_all_item_list_container,
            ConstraintSet.BOTTOM,
            ConstraintSet.PARENT_ID,
            ConstraintSet.BOTTOM
        )

        constraintSet.applyTo(layout)

        searchView.visibility = View.GONE
        swipeRefreshLayout.visibility = View.GONE

        return layout
    }

    return null
}

abstract fun fetchData()

abstract fun onItemClicked(item: RecyclerAdapter.Item)

}

ClientFragment实现此抽象类,它负责获取将填充所有小部件的数据。

class ClientFragment : BaseGridFragment() {
override fun onAttach(context: Context) {
    super.onAttach(context)

    (activity as AppCompatActivity).supportActionBar?.title = "Clients"

    fetchData()
}

override fun fetchData() {
    requestSender.sendRequest(context!!, "/api/clients", JSONArray()) { result ->
        when (result) {
            is RequestSender.RequestSenderResult.Success -> {
                if (result.data.length() != 1) {
                    return@sendRequest
                }

                recyclerAdapter.items.clear()

                val clients = result.data[0] as JSONArray
                for (i in 0 until clients.length()) {
                    val client = clients.get(i) as JSONArray
                    if (client.length() != 3) {
                        Log.e(
                            "ClientActivity",
                            "Invalid client data length while parsing client response. Skipping client."
                        )
                        continue
                    }

                    recyclerAdapter.items.add(
                        RecyclerAdapter.Item(
                            client[0] as String,
                            client[1] as String,
                            URL(client[2] as String)
                        )
                    )
                }

                // Clearing data and calling notifyDataSetChanged() is relatively expensive. If
                // number of items returned causes UI smoothness problem consider notifyDataSetChanged
                // for specific indexes.
                activity!!.runOnUiThread { recyclerAdapter.notifyDataSetChanged() }

                progressBar.visibility = View.GONE
                swipeRefreshLayout.visibility = View.VISIBLE
                searchView.visibility = View.VISIBLE
                swipeRefreshLayout.isRefreshing = false
            }
            is RequestSender.RequestSenderResult.Error -> {
                val alert = AlertDialog.Builder(context!!)
                alert.setPositiveButton("OK", null)
                when (result.error) {
                    is RequestSender.RequestSenderError.NetworkError -> {
                        alert.setTitle("Network Error")
                        alert.setMessage(result.error.description)
                    }
                    is RequestSender.RequestSenderError.ClientError -> {
                        alert.setTitle("Request Error")
                        alert.setMessage(result.error.description)
                    }
                    is RequestSender.RequestSenderError.InternalServerError -> {
                        alert.setTitle("Server Error")
                        alert.setMessage(result.error.description)
                    }
                    is RequestSender.RequestSenderError.UnrecognizedNetworkStatusCode -> {
                        alert.setTitle("Network Error")
                        alert.setMessage(result.error.description)
                    }
                    is RequestSender.RequestSenderError.UnableToDeserializeResponse -> {
                        alert.setTitle("Deserialization Error")
                        alert.setMessage(result.error.description)
                    }
                }
                activity!!.runOnUiThread {
                    alert.create().show()
                    progressBar.visibility = View.GONE
                    swipeRefreshLayout.visibility = View.VISIBLE
                    swipeRefreshLayout.isRefreshing = false
                }
            }
        }
    }
}

override fun onItemClicked(item: RecyclerAdapter.Item) {
    (activity as MainActivity).onClientClicked(item)
}

}

当我运行此代码时,BaseGridFragment中的ConstraintSet无法正常工作。当应用程序首次启动时,会有一个网络调用来获取一些数据。在获取数据时,我在屏幕中间显示了一个微调器。数据下载后,UI更改为在顶部显示搜索栏,在其下方显示CardView。

MainActivity中的根视图是ConstraintLayout,BaseGridFragment内部的主视图也是ConstraintLayout,它包含所有其他小部件。我已经对两个主要视图进行了颜色编码:绿色表示MainActivity中的布局,蓝色表示BaseGridFragment中的布局。

enter image description here enter image description here

基于我对supportFragmentManager的工作原理的理解,以下代码应使BaseGridFragment中的布局成为MainActivity中布局的直接子代。因此,我在BaseGridFragment中定义的任何引用ConstraintSet.PARENT_ID的约束都应起作用:

supportFragmentManager.beginTransaction()
            .add(R.id.constraint_layout_main_activity, ClientFragment(), "CLIENT_FRAGMENT")
            .commit(

如您从屏幕快照中看到的,蓝色区域没有按预期扩展为绿色:微调框未居中,并且CardView根本不在搜索栏下方显示。如果我重构代码,并且摆脱了所有片段,只是将BaseGridFragment布局中的所有内容都放到了活动中,那么一切都会正常进行,因此在这里我必须缺少一些有关片段的信息。

我已经找到了解决方案,但是我遇到的所有示例都使用XML定义其UI,然后在onCreateView()中使用充气器。

我正在以编程方式构建我的所有UI,而没有使用XML文件。我的主要UI类继承自AppCompatActivity(),并在UI类的主要部分使用了称为ClientFragment的片段...

android android-layout android-fragments kotlin android-constraintlayout
1个回答
0
投票

我看不到您将布局参数设置为主布局

© www.soinside.com 2019 - 2024. All rights reserved.