Disons que j'ai cette mise en page:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical">
<ImageButton
Android:id="@+id/add_dep_btn"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignParentEnd="true"
Android:layout_alignParentRight="true"
Android:layout_marginEnd="5dp"
Android:layout_marginRight="5dp"
Android:src="@Android:drawable/ic_input_add" />
<EditText
Android:id="@+id/add_dep_text"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_alignBottom="@id/add_dep_btn"
Android:layout_alignParentLeft="true"
Android:layout_alignParentStart="true"
Android:layout_alignTop="@id/add_dep_btn"
Android:layout_marginLeft="5dp"
Android:layout_marginStart="5dp"
Android:layout_toLeftOf="@id/add_dep_btn"
Android:layout_toStartOf="@id/add_dep_btn" />
<Android.support.v7.widget.RecyclerView
Android:id="@+id/dep_list"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_below="@id/add_dep_btn" />
<TextView
Android:id="@+id/empty_text"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_below="@id/add_dep_text"
Android:layout_margin="20dp"
Android:gravity="center"
Android:text="@string/no_dep"
Android:textSize="22sp" />
</RelativeLayout>
Et je l'utilise dans un DialogFragment:
class DepartmentChoiceDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity)
builder.setTitle(R.string.choose_or_create_dep)
.setView(R.layout.department_chooser_dialog)
.setNegativeButton(Android.R.string.cancel, { d, i ->
d.cancel()
})
return builder.create()
}
}
si je me réfère au widget en utilisant synthétique:
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
dep_list.layoutManager = LinearLayoutManager(activity)
dep_list.itemAnimator = DefaultItemAnimator()
dep_list.setHasFixedSize(true)
}
J'ai eu cette erreur au moment de l'exécution:
Java.lang.NullPointerException: tentative d'appeler la méthode virtuelle 'Android.view.View Android.view.View.findViewById (int)' sur une référence d'objet null. sur MyDialog ._ $ _ findCachedViewById (DepartmentChoiceDialog.kt: 0)
Je ne comprends pas comment utiliser synthétique dans le cas DialogFragment. Cela fonctionne très bien dans Fragment and Activity.
J'ai trouvé un moyen qui fonctionne pour les dialogues personnalisés.
class ServerPickerDialogFragment: AppCompatDialogFragment()
{
// Save your custom view at the class level
lateinit var customView: View;
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View?
{
// Simply return the already inflated custom view
return customView
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Inflate your view here
customView = context!!.layoutInflater.inflate(R.layout.dialog_server_picker, null)
// Create Alert Dialog with your custom view
return AlertDialog.Builder(context!!)
.setTitle(R.string.server_picker_dialog_title)
.setView(customView)
.setNegativeButton(Android.R.string.cancel, null)
.create()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?)
{
super.onViewCreated(view, savedInstanceState)
// Perform remaining operations here. No null issues.
rbgSelectType.setOnCheckedChangeListener({ _, checkedId ->
if(checkedId == R.id.rbSelectFromList) {
// XYZ
} else {
// ABC
}
})
}
}
Il semble que cela ne soit pas encore supporté par défaut, mais j'ai trouvé le moyen le plus simple de le faire. Dans une classe de dialogue de base:
protected abstract val containerView: View
override fun getView() = containerView
Dans une sous-classe:
override val containerView by unsafeLazy {
View.inflate(context, R.layout.dialog_team_details, null) as ViewGroup
}
Vous pouvez ensuite utiliser les vues synthétiques comme vous le feriez normalement et utiliser la variable containerView
comme vue de votre boîte de dialogue.
Passer à onCreateView implementation
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.department_chooser_dialog, container, false)
}
et utiliser un titre personnalisé (TextView) et annuler (Button) dans le department_chooser_dialog
onActivityCreated sera exécuté après onCreateView et ira très bien.
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
dep_list.layoutManager = LinearLayoutManager(activity)
dep_list.itemAnimator = DefaultItemAnimator()
dep_list.setHasFixedSize(true)
}
Donc, je ne suis pas sûr si cela a été résolu ... Je viens de découvrir cela. Si vous avez une vue de dialogue personnalisée, créez une classe qui étend DialogFragment et utilisez l'objet "dialogue" pour importer des vues dans la présentation. J'utilise Android Studio 3.1.3
et Kotlin version 1.2.41
au moment de la rédaction.
import kotlinx.Android.synthetic.main.your_custom_layout.*
class SelectCountryBottomSheet : BottomSheetDialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val dialog = super.onCreateDialog(savedInstanceState) as BottomSheetDialog
dialog.setContentView(R.layout.your_custom_layout)
dialog.some_custom_close_button.setOnClickListener { dismiss() }
return dialog
}
}
Parce que la valeur par défaut de la vue est fragment (la méthode kotlin generate _ $ _ findCachedViewById), mais si nous créons View à partir du dialogue, lead en fragment view est null, nous ne pouvons donc pas utiliser directement default xxx, mais nous pouvons utiliser dialog.xxx xxx
Déplacez votre code de onActivityCreated
à onViewCreated
, méthode .
import kotlinx.Android.synthetic.main.department_chooser_dialog.dep_list
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
dep_list.apply {
layoutManager = LinearLayoutManager(activity)
itemAnimator = DefaultItemAnimator()
setHasFixedSize(true)
}
}
En fait, je n'ai pas approfondi le code généré et il y a peut-être un bug.
La réponse précédente ne fonctionnera pas, car onViewCreated n'est pas appelé lorsque vous utilisez onCreateDialog. Vous devez d'abord importer kotlinx ... department_chooser_dialog. view . Dep_list, puis l'utiliser comme suit:
import kotlinx.Android.synthetic.main.department_chooser_dialog.view.dep_list
...
class DepartmentChoiceDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val builder = AlertDialog.Builder(activity)
val dialog = inflater.inflate(R.layout.department_chooser_dialog, null)
dialog.dep_list.layoutManager = LinearLayoutManager(activity)
dialog.dep_list.itemAnimator = DefaultItemAnimator()
dialog.dep_list.setHasFixedSize(true)
builder.setTitle(R.string.choose_or_create_dep)
.setView(dialog)
...
Le code kotlin dans un fragment comme celui-ci:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.your_layout, container, false).apply {
mContentView = this
button1.setOnClickListener {
//do something
}
}
}
Après avoir décompilé le bytecode, vous pouvez voir l’implémentation des propriétés synthétiques:
((Button)this._$_findCachedViewById(id.button1))
Et de la méthode _$_findCachedViewById
:
public View _$_findCachedViewById(int var1) {
if (this._$_findViewCache == null) {
this._$_findViewCache = new HashMap();
}
View var2 = (View)this._$_findViewCache.get(var1);
if (var2 == null) {
View var10000 = this.getView();
if (var10000 == null) {
return null;
}
var2 = var10000.findViewById(var1);
this._$_findViewCache.put(var1, var2);
}
return var2;
}
donc la magie est juste la this.getView()
. La propriété Fragment.mView
est attribuée après Fragment.onCreateView(inflater, container, savedInstanceState)
, si vous utilisez Kotlin Synthetic Properties dans la méthode onCreateView (), il y aura un NPE. Code de FragmentManager.moveToState()
:
case Fragment.CREATED:
...
f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container,
f.mSavedFragmentState);
...
Pour réparer le NPE, assurez-vous que la méthode getView
renvoie une vue non NULL.
private var mContentView: View? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.your_layout, container, false).apply {
mContentView = this
}
}
override fun getView(): View? {
return mContentView
}
et au rappel de cycle de vie onDestroyView()
, définissez mContentView
sur null.
override fun onDestroyView() {
super.onDestroyView()
mView = null
}