Android scrollbars appear inside views after opening preferencescreen - android

I use navigation architecture component and if I navigate to the settings page and then I go back then lines and scrollbars appear on views. The PreferenceScreen is very simple only contains a ListPreference.
SettingsFragment:
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
init()
}
private fun init() {
(activity as AppCompatActivity?)?.supportActionBar?.show()
activity?.fab?.visibility = View.GONE
(activity as AppCompatActivity?)?.nav_view?.visibility = View.GONE
activity?.app_bar?.setExpanded(true, true)
val toolbarParams = activity?.toolbar?.layoutParams as AppBarLayout.LayoutParams
toolbarParams.scrollFlags = 0
} }
xml:
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory app:title="General">
<ListPreference
app:key="app_theme_color"
app:title="Theme"
app:defaultValue="black"
app:entries="#array/color_entries"
app:entryValues="#array/color_values"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>

Related

Bottom navigation bar listener not working

So i just got started with android development a couple weeks ago, while trying to make navigation between two fragments with a bottom nav bar, for some reasons the click listener is just not working, no errors, no warnings, compiles no problem but it might be some logic problem? here's the code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragmentHome = HomeFragment()
val fragmentProfile = ProfileFragment()
replaceCurrentFragment(fragmentHome)
NavigationBarView.OnItemSelectedListener { item ->
when(item.itemId) {
R.id.page_home -> {
Log.i("NavBar","Home pressed")
replaceCurrentFragment(fragmentHome)
true
}
R.id.page_profile -> {
Log.i("NavBar","Profile pressed")
replaceCurrentFragment(fragmentProfile)
true
}
else -> {
Log.i("NavBar","Error?")
false
}
}
}
}
private fun replaceCurrentFragment(fragment: Fragment) =
supportFragmentManager.beginTransaction().apply {
replace(R.id.flFragment, fragment)
commit()
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/flFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="#+id/bottom_navigation"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.bottomnavigation.BottomNavigationView
app:labelVisibilityMode="selected"
android:id="#+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="#menu/bottom_navigation_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
Menu:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/page_home"
android:icon="#drawable/ic_home"
android:title="Home"/>
<item
android:id="#+id/page_profile"
android:icon="#drawable/ic_profile"
android:title="Profile"/>
</menu>
the main page does get initialized on the home fragment, but when i click the nav bar buttons, nothing happens so the problem is in that listener part, copy pasted from the docs yet it doesn't work.
i also have a bug where the layout editor doesn't show the nav bar contents, so my ide might be glitched? would appreciate any help.
Replace "NavigationBarView" with your actual bottomNavigationView id.
This would work,
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val fragmentHome = HomeFragment()
val fragmentProfile = ProfileFragment()
replaceCurrentFragment(fragmentHome)
val myBottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_navigation)
myBottomNavigationView.OnItemSelectedListener { item ->
when(item.itemId) {
R.id.page_home -> {
Log.i("NavBar","Home pressed")
replaceCurrentFragment(fragmentHome)
true
}
R.id.page_profile -> {
Log.i("NavBar","Profile pressed")
replaceCurrentFragment(fragmentProfile)
true
}
else -> {
Log.i("NavBar","Error?")
false
}
}
}
}
private fun replaceCurrentFragment(fragment: Fragment) =
supportFragmentManager.beginTransaction().apply {
replace(R.id.flFragment, fragment)
commit()
}
}

Android overflow menu text not appearing

I am trying to put a checkable overflow menu into my toolbar. The menu renders with the check boxes, but the text does not appear. Android studio renders the menu as intended but it does not on my AVD. I have tried changing the text color of the menu and using an action layout.
[![Intended render of menu][1]][1]
[![Actual render of menu][2]][2]
menu_main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"
android:layout_height="wrap_content"
android:layout_width="wrap_content">
<item
android:id="#+id/tab_1"
android:checkable="true"
android:title="#string/tab_1"
app:showAsAction="never|withText"
android:actionLayout="#layout/action_layout"/>
<item
android:id="#+id/tab_2"
android:checkable="true"
android:title="#string/tab_2"
android:visible="true"
app:showAsAction="never|withText" />
<item
android:id="#+id/tab_3"
android:checkable="true"
android:title="#string/tab_3"
android:visible="true"
app:showAsAction="never|withText" />
</menu>
activity_main.kt
lateinit var sectionsPagerAdapter: SectionsPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sectionsPagerAdapter = SectionsPagerAdapter(this, supportFragmentManager)
val viewPager: ViewPager = findViewById(R.id.view_pager)
viewPager.adapter = sectionsPagerAdapter
val tabs: TabLayout = findViewById(R.id.tabs)
tabs.setupWithViewPager(viewPager)
val fab: FloatingActionButton = findViewById(R.id.fab)
val toolBar: Toolbar = findViewById(R.id.tool_bar)
setSupportActionBar(toolBar)
toolBar.showOverflowMenu()
var position: Int = 0
class onTabSelectListen : TabLayout.OnTabSelectedListener{
override fun onTabReselected(tab: TabLayout.Tab?) {
if (tab != null) {
position = tab.position
};
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
Log.d("","")
}
override fun onTabSelected(tab: TabLayout.Tab){
position = tab.position;
}
}
tabs.addOnTabSelectedListener(onTabSelectListen())
fab.setOnClickListener { view ->
Snackbar.make(view, "Reloading...", Snackbar.LENGTH_SHORT)
.setAction("Action", null).show()
fab.animate()
.setDuration(500)
.rotationBy(-360f)
reload()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main,menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
val itemId = item.itemId
if (item.isChecked) {
//TODO("UNCHECKD LOGIC")
item.isChecked = false //Toggles checkbox state.
} else {
//TODO("CHECKED LOGIC")
item.isChecked = true
}
return super.onOptionsItemSelected(item)
}
fun reload(){
(sectionsPagerAdapter.getItem(sectionsPagerAdapter.GOOGLE_POSITION) as WebFragment).reloadWebView()
(sectionsPagerAdapter.getItem(sectionsPagerAdapter.TWITTER_POSITION) as WebFragment).reloadWebView()
}
}```
[1]: https://i.stack.imgur.com/sEOFd.png
[2]: https://i.stack.imgur.com/Jqjwb.png
Try setting following property in Item:
android:showAsAction="ifRoom"
Instead of:
app:showAsAction="never|withText"
Adding this as an attribute under <toolbar> worked for me
app:popupTheme="#style/Theme.Assignment1.PopupOverlay"

PreferenceFragments not in the same FragmentManager?

We have a PreferenceFragmentCompat, and with a tap on a preference, we want to switch from the current PreferenceFragmentCompat to a new PreferenceFragmentCompat. (To have certain settings on a new screen).
However, regardless of what we have tried, we keep running into the following error:
Fragment declared target fragment that does not belong to this
FragmentManager
MainActivity.kt
class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback, PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_preferences
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onPreferenceStartFragment(caller: PreferenceFragmentCompat, pref: Preference): Boolean {
val args = pref.extras
val fragment = supportFragmentManager.fragmentFactory.instantiate(
classLoader,
pref.fragment)
fragment.arguments = args
fragment.setTargetFragment(caller, 0)
// Replace the existing Fragment with the new Fragment
supportFragmentManager.beginTransaction()
.replace(R.id.nav_host_fragment, fragment)
.addToBackStack(null)
.commit()
return true
}
}
PreferenceFragement1.kt
class PreferencesFragment1 : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences1, rootKey)
}
}
PreferenceFragment2.kt
class PreferenceFragment2 : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences2, rootKey)
}
}
Preferences1.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<PreferenceCategory
android:title="Category"
app:iconSpaceReserved="false">
<Preference
app:key="pref2"
app:iconSpaceReserved="false"
android:title="Open"
app:fragment="com.testapp.ui.preferences.Preference2"/>
</PreferenceCategory>
</PreferenceScreen>
Preferences2.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
</PreferenceScreen>
The stacktrace shows the following:
java.lang.IllegalStateException: Fragment Preference2{496ebb9} (1b91d8df-58c0-485a-96f9-d392fcef528b) id=0x7f09008d} declared target fragment Preference1{b6337c1} (97aa1b0e-d5fa-4995-b0ba-e89ad0ea5ce0) id=0x7f09008d} that does not belong to this FragmentManager!
at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1148)
at androidx.fragment.app.FragmentTransition.addToFirstInLastOut(FragmentTransition.java:1255)
at androidx.fragment.app.FragmentTransition.calculateFragments(FragmentTransition.java:1138)
at androidx.fragment.app.FragmentTransition.startTransitions(FragmentTransition.java:136)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1989)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1947)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1849)
at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6718)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
We are using androidx.preference:preference-ktx:1.1.1.
Can some give us a concise explanation what exactly is causing this problem, and how we can solve it?
We already looked at the following (related) posts, without any success:
Fragment declared target fragment that does not belong to this FragmentManager
How to open a new PreferenceFragment from current one, using the new Android-X API?
https://developer.android.com/guide/topics/ui/settings/organize-your-settings
When you create a Fragment via the navigation graph, it is a child fragment of the NavHostFragment. It specifically is not the activity's supportFragmentManager. This is why the target fragment isn't found - you're using the wrong FragmentManager.
However, you should not use app:fragment or onPreferenceStartFragment when you're using Navigation. Instead, your PreferencesFragment1 should set a click listener on your Preference and have it call navigate() directly.
class PreferencesFragment1 : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences1, rootKey)
findPreference<Preference>("pref2")?.setOnPreferenceClickListener {
// Use whatever ID that is associated with
// PreferenceFragment2 in your navigation graph
findNavController().navigate(R.id.pref2)
}
}
}
Preferences1.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<PreferenceCategory
android:title="Category"
app:iconSpaceReserved="false">
<Preference
app:key="pref2"
app:iconSpaceReserved="false"
android:title="Open"/>
</PreferenceCategory>
</PreferenceScreen>

I have a gap on top of my preferences fragment, dunno what causes it

I followed this guide https://developer.android.com/guide/topics/ui/settings to create my preferences page, but when I navigate to my settings page, I get an empty row in my settings fragment just before the preferencescreen items, like in the picture https://imgur.com/a/KbVrIHr
This is my code;
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, SettingsFragment())
.commit()
}
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.preferences)
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/settings_container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.actionbar.settings.SettingsActivity">
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory
app:iconSpaceReserved="false"
app:title="Theme">
<SwitchPreferenceCompat
app:iconSpaceReserved="false"
app:key="switch"
app:summary="Enable dark theme."
app:title="Dark Theme" />
</PreferenceCategory>
</androidx.preference.PreferenceScreen>

SearchView not filling entire Actionbar by default, and not responding to clicking

I've looked around and haven't been able to find exactly what I'm looking for. A little help would be appreciated. I'm attempting to implementing a SearchWidget as shown here. I'm getting a bizarre setup however. The search Icon is not even showing up, on the far right there is three vertical dots as part of the toolbar, and when I click on those a Search box appears. But clicking on that doesn't register anything through setOnClickListener or setOnQueryTextFocusChangeListener. Any help would be much appreciated. Like so:
toolbar when opening the app
popup search menu - doesn't do anything when I click on it
Here's what I've got
My SearchActivity:
class SearchCategoryActivity : MvvmActivity<SearchCategoryViewModel>() {
companion object {
private const val CATEGORY = "category"
fun newIntent(context: Context): Intent {
return Intent(context, SearchCategoryActivity::class.java)
}
}
#Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
val listofCategories : List<Category>? = null
private lateinit var adapter: CategoryGroupAdapter
var browsingData : List<Category>? = null
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_search_category)
setSupportActionBar(toolbar)
val actionBar = supportActionBar
actionBar?.setDisplayHomeAsUpEnabled(true)
adapter = CategoryGroupAdapter(this)
adapter.setOnClickListener { category, _ -> onCategoryClick(category) }
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.itemAnimator = DefaultItemAnimator()
recyclerView.adapter = adapter
toolbar.setNavigationOnClickListener { finish() }
//clearImageView.setOnClickListener { searchEdiText.text = null }
addFab.setOnClickListener { onAddFabClick() }
viewModel.loadCategories.subscribe(this, object : FlowableSubscriber<List<Category>> {
override fun onNext(data: List<Category>) {
browsingData = data
onLoadCategories(data)
}
override fun onComplete() {
Timber.error { "onComplete" }
}
override fun onError(error: Throwable) {
onLoadCategoriesFailed(error)
}
})
LceAnimator.showLoading(loading, content, error)
viewModel.loadCategories()
System.out.println("Here")
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the options menu from XML
val inflater = menuInflater
inflater.inflate(R.menu.menu_search, menu)
// Get the SearchView and set the searchable configuration
val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager
val searchView = menu.findItem(R.id.action_search).actionView as SearchView?
// Assumes current activity is the searchable activity
searchView?.setSearchableInfo(searchManager.getSearchableInfo(componentName))
searchView?.setIconifiedByDefault(false) // Do not iconify the widget; expand it by default
searchView?.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
System.out.println("clicked")
}
})
searchView?.setOnQueryTextFocusChangeListener(object : View.OnFocusChangeListener {
override fun onFocusChange(v: View?, hasFocus: Boolean) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
My SearchActivity.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background">
<!-- Dummy item to prevent AutoCompleteTextView from receiving focus -->
<!-- :nextFocusUp and :nextFocusLeft have been set to the id of this component
to prevent the dummy from receiving focus again -->
<com.google.android.material.appbar.AppBarLayout
android:id="#+id/appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/ThemeOverlay.AppCompat.Dark">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize">
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="#string/appbar_scrolling_view_behavior">
<include layout="#layout/layout_loading" />
<include layout="#layout/layout_search" />
<include layout="#layout/layout_error" />
</FrameLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
My searchable.xml:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="#string/app_name"
android:hint="#string/search_hint" />
My search_menu.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:layout_width="match_parent"
android:icon="#android:drawable/ic_search_category_default"
android:showAsAction="always"
android:title="#string/search"
app:queryBackground="#color/background"/>
</menu>
Try adding app instead of android and using v7:
app:actionViewClass="android.support.v7.widget.SearchView"
Also, to make it collapsable:
app:showAsAction="always|collapseActionView"
And no need for android:layout_width="match_parent".
You can try this so it fill would fill the toolbar
searchMenuItem.actionView.also {
it.post {
it.layoutParams = it.layoutParams.apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
}
}
}

Categories

Resources