I have a custom ConstraintLayout Myword. when I set the visibility of myword1 to GONE inside kotlin fun doOnLayout, it becomes invisible but myword2 doesn't move down.
But if I set its visibility to GONE in XML or outside doOnLayout, it works as intended.
<learnprogramming.academy.relaf.Myword
android:id="#+id/myword1"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<learnprogramming.academy.relaf.Myword
android:id="#+id/myword2"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="#id/myword1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
Source code:
lateinit var bannerword : MutableList<Myword>
lateinit var swippon : ConstraintLayout
fun updatewords{
swippon.doOnLayout {
if (swippon.height>1000) bannerword[0].visibility = View.GONE}
class PhrasesFragment: Fragment() {
companion object {
fun newInstance(): PhrasesFragment {
return PhrasesFragment()
}
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.inglesa_screen, container, false) }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bannerword=mutableListOf(myword1,myword2)
swippon=parent
updatewords()
}
}
doOnLayout function when layout is laid out calculates parent Layout height and eventually removes myword1. I actually solved changing doOnLayout with Handler(Looper.getMainLooper()).post{} but is wrong with doOnLayout? How should i have used it in the correct way?
Related
i manually created a fragment. but cant declare a component like web view or button. when i paste and edit "val webview: WebView ..." there is error "Fragment(R.layout.fragment_htmlviewer)" too. i dont know how to do, when i create from android studio, it looks like very complicated. so i watched a video and this is more easy but cant declare components. im very beginner so help me please... my code:
fragment_htmlviewer.xml
<WebView
android:id="#+id/htmlViewer"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/floating_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
android:contentDescription="#string/fabdescription"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:srcCompat="#drawable/ic_left_arrow_icon" />
HtmlViewerFragment.kt
class HtmlViewerFragment : Fragment(R.layout.fragment_htmlviewer) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return super.onCreateView(inflater, container, savedInstanceState)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val webview: WebView = getView()!!.findViewById<View>(R.id.htmlViewer) as WebView
}
}
I recommend you to use the binding structure, it is a more preferred structure today.
build.gradle(module)
buildFeatures {
viewBinding true
dataBinding true
}
HtmlViewerFragment
private var _binding: FragmentHtmlViewerBinding? = null
private val binding
get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentHtmlViewerBinding.inflate(inflater, container, false)
//.. this is write code
binding.apply{
//eg:
htmlViewer.setOnClickListener{
}
}
return binding.root
}
override fun onStart() {
super.onStart()
htmlViewer = requireView().findViewById(R.id.htmlViewer) as WebView
htmlViewer!!.loadUrl("https://www.google.com")
}
this is solution.
htmlViewer = requireView().findViewById(R.id.htmlViewer) as WebView
fixed
I am trying to create modal bottom sheet dialog to show a list of items which will be scrollable.
dialog_bottom_example.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:id="#+id/container"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="vertical"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Items in LinearLayout is getting added dynamically based on list size as below:
ExampleDialogBottom:
class ExampleDialogBottom: BottomSheetDialogFragment() {
private lateinit var binding: DialogExampleBinding
private var skusItems = mutableListOf<SkuItem>();
companion object {
internal const val TAG = "ExampleDialogBottom"
#JvmStatic
fun newInstance(nonEligibleErxItem: NonEligibleErxItem) = NonEligibleBottomDialog
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DialogExampleBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
configureSkuItems()
}
private fun configureSkuItems() {
if (!skuItems.isNullOrEmpty()) {
val inflater = LayoutInflater.from(context)
for (sku in skuItems) {
val skuItemView = SingleSkuItemViewBinding.inflate(inflater, null, false)
skuItemView.skuImage.setImageWithVisibility(sku.imageUrl)
skuItemView.skuTitle.setTextWithVisibility(sku.name)
binding.container.addView(skuItemView.root)
}
binding.container.visibility = View.VISIBLE
} else {
binding.container.visibility = View.GONE
}
}
ExmpaleActivity:
button.setOnClickListener {
ExampleDialogBottom.newInstance().show(getSupportFragmentManager(),
ExampleDialogBottom.TAG);
}
However, when I click on button, a transparent dialog shows up, no content is showing.
When I removed match-contraint and changed it match-parent or wrap-content, it's working as expected.
It would be great if someone could help? Thanks in advance.
Why do buttons in Fragments to not get triggered? I've already spent about 5 hours on this, but no onClick / onFocusListener will trigger
Edit: Code
So this Fragment(s) is on a ViewPager2 on my MainActivity and
it just wont trigger any Callback Methods. I have also tried to but those onClick initializations everywhere
Fragment:
class SearchFragment : Fragment() {
private lateinit var searchBinding: FragmentSearchBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
searchBinding = FragmentSearchBinding.inflate(layoutInflater)
interface OnSearch {
fun onArticleSelected(position: Int)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_search, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var test = activity?.findViewById<TabLayout>(R.id.tab_layout)
searchBinding.searchBar.setOnFocusChangeListener{view, hasFocus ->
if (hasFocus){
if (test != null) {
test.isVisible = false
}
Log.d("SearchFragment", "onFocus")
}else{
if (test != null) {
test.isVisible = true
}
}
}
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".ui.main.search.SearchFragment"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.button.MaterialButton
android:id="#+id/testButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<EditText
android:id="#+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="20sp"
android:hint="Search"
android:focusedByDefault="true"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/searchRecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
</FrameLayout>
Try something like this
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) {
super.onCreateView(view, savedInstanceState)
val binding = FragmentSearchBinding.inflate(inflater, container, false);
val view = binding.root
// Set binding
return view;
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.findViewById(R.id.searchBar).setOnFocusChangeListener { view, hasFocus ->
}
}
After rotation, one old page is displayed, followed by new pages.
Before rotation 1.
After rotation 2.
Layout with ViewPager:
<RelativeLayout ...
<androidx.viewpager.widget.ViewPager
android:id="#+id/pager"
android:overScrollMode="never"
android:layout_marginStart="16dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="10dp"
android:layout_height="match_parent"
android:layout_width="match_parent">
</RelativeLayout>
Fragment with this layout:
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val view = inflater.inflate(layoutId(), container, false)
view.findViewById<ViewPager>(R.id.pager).adapter = TextPagerAdapter(activity!!.supportFragmentManager, listOf())
return view
}
TextPagerAdapter:
override fun getItem(position: Int): Fragment = PageFragment.newInstance("sssssss ssss $position")
override fun getCount() = 5//pageText.size
}
PageFragment:
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {
val view = inflater.inflate(layoutId(), container, false)
view.findViewById<TextView>(R.id.page_content_textView).text = arguments!!.getCharSequence(PAGE_TEXT)
return view
}
I forgot to check if the content fragment is already created.
The solution is to check if the savedInstanceState == null. And create new fragment if that condition is true.
In MyActivity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if(savedInstanceState == null) this.supportFragmentManager.beginTransaction()
.add(containerViewId, CollectionDemoFragment()).commit()
}
I have MainFragment, and inside my fragment I added my CustomButton custom view. And, onViewCreated, I setOnClickListener to the view. But, the fragmenet does not respond to the click.
ButtonWithImage
class ButtonWithImage(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
init {
val view = View.inflate(context, R.layout.item_custom_btn, this)
val attributes = context.obtainStyledAttributes(attrs, R.styleable.BadgeIcon)
view.btn_image.setImageDrawable(attributes.getDrawable(R.styleable.BadgeIcon_image))
view.btn_text.setText(attributes.getResourceId(R.styleable.BadgeIcon_text, 0))
attributes.recycle()
}
}
fragment_main.xml
...
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal">
<corn.transaction.custom_view.ButtonWithImage
android:id="#+id/my_cards"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:image="#drawable/ic_my_cards"
app:text="#string/btn_text_my_cards"/>
<corn.transaction.custom_view.ButtonWithImage
android:id="#+id/transactions"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:image="#drawable/ic_transactions"
app:text="#string/btn_text_transactions"/>
</LinearLayout>
...
MainFragment.kt
class MainFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_main, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
my_cards.setOnClickListener { logMessage("loooooog") }
}
I think you can fix it by:
Adding focusable=false and clickable=false to your btn_image and btn_text
Adding focusable=true and clickable=true to your root view of this custom layout (also give it id -> lets say custom_button_container)
call my_cards.findViewById<LinearLayout>(R.id.custom_button_container).setOnClickListener { logMessage("loooooog") }
The optimal solution is making all views in XML clickable and focusable false.
You can use the following code:
my_cards.setOnClickListener { logMessage("loooooog") }
As all views are not clickable and focusable, they do ignore clicks, but not the custom view itself.