我正在以编程方式构建我的所有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中的布局。
基于我对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的片段...
我看不到您将布局参数设置为主布局