I'm writing android app, using fragments.
There are two main ways to navigate up or back.
picture of the screen
The first is to use the arrow on the navigation bar (marked with the number 1 in the picture)
The second use the system back button (marked with the number 2)
I wrote:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
...
requireActivity().onBackPressedDispatcher.addCallback(this) {
findNavController().navigate(R.id.action_updateFragment_to_listFragment)
...
}
and it works just fine, but only for system back button(2).
How can I override action caused by click on the back arrow from navigation bar(1)?
thanks!!!
Ok, I've got this.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == android.R.id.home) {
Toast.makeText(requireContext(), "the answer", Toast.LENGTH_SHORT).show()
}
return super.onOptionsItemSelected(item)
}
I hope this post will help someone in the future.
Related
I have a login activity with navigation fragments , one is the splash screen and then navigate to Login Fragment this is the Launcher Activity and it checks if the user is already logged in and then start de Initial Activity if is already logged in.
In the Initial Activity i have a navigation fragments but when the user press the back button the Activity Launch start instead of close the activity. I want the user to close the app like the same behavior that occurs when back button is pressed on the launcher activity. How do i achieve this?
This is the splash fragment in the Launcher Activity:
fun initListeners() {
val DURATION = 2500
user_app.toString()
val handler = Handler()
handler.postDelayed({
if (user_app.isEmpty() && pwd_app.isEmpty()) {
navigationToLogin()
} else {
Toast.makeText(safeActivity, "SesiĆ³n iniciada ${OPERATOR_APP.getPreferenceToString().toString()}", Toast.LENGTH_SHORT).show()
startActivity(Intent(safeActivity,XTInitActivity::class.java))
}
}, DURATION.toLong())
}
fun navigationToLogin() {
val navigate = SplashFragmentDirections.actionSplashFragmentToXTLoginFragment()
findNavController().navigate(navigate)
}
}
I try when the methon onBackPressed whit its callbacks but its now deprecated for most recent API
I think you should make a separate activity for splash and keep the splash activity as the launcher instead of Login activity and and then if the user is not signed in then only go to Loginactivity else start the MainActivity (XTInitActivity in your case)
However if you need to make LoginActivity as the launcher activity then use the following:
override fun onBackPressed(){
super.onBackPressed()
exitProcess(0)
}
override onBackPressed in Initial Activity
override fun onBackPressed() {
super.onBackPressed()
exitProcess(0)
}
I have a project where we display a graph, this graph is in an Box which is scrollable.
By opening the view, we need to center the root node which causes the problem currently.
Determining the position and setting the values of the states is currently done the following way:
.onGloballyPositioned { coordinates -> scrollBy = coordinates.positionInParent().y - dpstate!!.scrollState.firstVisibleItemScrollOffset
}
.onFocusChanged {
if(it.isFocused ){
print("is focused")
scope.launch { dpstate!!.scrollState.animateScrollBy(scrollBy)
dpstate!!.offsetState.value = Offset(leftX.toFloat(),dpstate!!.offsetState.value.y)
}
}
}
in the modifier of the box.
The state dpstate is an instance of the following:
data class DisplayState(
val scrollState: LazyListState,
val scaleState: MutableState<Float>,
val offsetState: MutableState<Offset>,
val editState: MutableState<Boolean>,
val showInfo:Map<Int, MutableState<Boolean>>,)
Important is, that I need to center by opening it, not by clicking a button.
My try was in the calling code of all of this the following code:
DisposableEffect(Unit){
com.github.tukcps.appel.ui.rendering.focusRequester!!.requestFocus()
onDispose { }
}
There is no exception, it just don't do anything, thanks for your help.
I have a nested Recycler lists which don't have ~~scrolling~~ & nestedScrollingEnabled=false. I'm attempting to swipe up and click on the recycler item by it's text. Having issues with determining when to swipe and how far.
UPDATE: This may have scrolling, I may need to specify the ViewHolder of the Item with text instead of the view with text... Experimenting...
parent_recycler_list
recycler_list
List item A
List item B
recycler_list
List item A
List item B
So far I am able to find the item and try to click on it:
Espresso.onView(
CoreMatchers.allOf(
ViewMatchers.withId(R.id.recycler_list),
ViewMatchers.hasDescendant(recyclerViewItemWithText(text))
)
).perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
recyclerViewItemWithText(text),
ViewActions.click()
)
)
fun recyclerViewItemWithText(text: String) = object : BoundedMatcher<View, View>(View::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("Searching for text with: $text")
}
override fun matchesSafely(item: View?): Boolean {
val views = ArrayList<View>()
item?.findViewsWithText(views, text, View.FIND_VIEWS_WITH_TEXT)
return when (views.size) {
1 -> true
else -> false
}
}
}
This only works by it self when the list item is displayed.
I have tried to swipe until the view item is displayed:
Espresso.onView(ViewMatchers.withId(R.id.parent_recycler_list)).perform(
ViewActions.repeatedlyUntil(
ViewActions.swipeUp(),
Matchers.allOf(
ViewMatchers.hasDescendant(ViewMatchers.withText(text)),
isCompletelyDisplayed()
), 10
)
)
This will always swipe at least once... and can swipe past the view item I'm looking for.
Is there a way I can be more precise in when and how far to swipe?
I'm a bit of a novice still and don't know much about custom swipe actions on view holders. Thanks
When trying to use nestedScrollTo()
java.lang.RuntimeException: Action will not be performed because the
target view does not match one or more of the following constraints:
(view has effective visibility=VISIBLE and is descendant of a: (is
assignable from class: class androidx.core.widget.NestedScrollView))
You can simply use ViewActions.scrollTo() if your nested recycler views do not have nested scrolling enabled, but you'll need to tweak the action first because it does not support NestedScrollView:
fun nestedScrollTo(): ViewAction = object : ViewAction {
private val scrollTo = ViewActions.scrollTo()
override fun getConstraints(): Matcher<View> {
return Matchers.allOf(
ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE),
ViewMatchers.isDescendantOfA(Matchers.anyOf(ViewMatchers.isAssignableFrom(NestedScrollView::class.java))))
}
override fun getDescription(): String = scrollTo.description
override fun perform(uiController: UiController, view: View) = scrollTo.perform(uiController, view)
}
Then use the new custom action to scroll, for example:
onView(withText("query")).perform(nestedScrollTo(), click())
Avoid using swipe in this use case if possible, they can be unreliable at times.
6 months later I figured out a bit more about Recycler lists and that I was trying to use them wrong, or at least figured out which Recycler actions work (some don't seem to work at all). This had nothing to do with Nested scrolling even though I have nested recycler lists.
Needed to use a swipe up action as a back up for when the list doesn't exist in the hierarchy.
Also there is a Potential infinite loop.
fun tapRecyclerItem(titleText: String) {
val parentList by lazy { onView(withId(R.id.parent_recycler_list)) }
try {
//Try to scroll to the item in the child list
onView(allOf(
withId(R.id.recycler_list),
hasDescendantWithText(titleText)
)).perform(
RecyclerViewActions.actionOnItem<RecyclerView.ViewHolder>(
hasDescendantWithText(titleText),
ViewActions.scrollTo()
)
)
// Tap the title
onView(allOf(withId(R.id.title), withText(titleText))).tap()
} catch (ex: NoMatchingViewException) {
// Swipe up and try again
parentList.perform(swipeCenterUp())
tapRecyclerItem(titleText)
}
}
fun hasDescendantWithText(text: String): Matcher<View> {
return Matchers.allOf(
hasDescendant(withText(text)),
withEffectiveVisibility(VISIBLE)
)
}
fun swipeCenterUp(): ViewAction? {
return ViewActions.actionWithAssertions(
GeneralSwipeAction(
Swipe.FAST,
GeneralLocation.CENTER,
GeneralLocation.TOP_CENTER,
Press.FINGER
)
)
}
I am learning Android programing, and I can not figure it out how to open settings fragment when button is clicked.
This fragment is not in the navigation map, so it is not possible to connect them in navigation and to use findNavController().navigate(actionFromTo)
As explained on developer guide: https://developer.android.com/guide/topics/ui/settings
I have created fragment:
class PreferencesFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.preferences, rootKey)
}
}
What I need to write in click listener to enter settings fragment?
Click listener is:
binding.buttonSettings.setOnClickListener {
}
I have tried with to use code in developers guide:
binding.buttonSettings.setOnClickListener {
val fragmentManager: FragmentManager? = activity?.supportFragmentManager
fragmentManager?.beginTransaction()?.replace(R.id.preferencesFragment, PreferencesFragment())?.commit()
}
But program crashes when button is pressed, with error:
No view found for...
The issue seems to be the content ID you want to replace, therefore you need to pass the current content ID you want to replace
see below code, use android.R.id.content instead of R.id.preferencesFragment
binding.buttonSettings.setOnClickListener {
val fragmentManager: FragmentManager? = activity?.supportFragmentManager
fragmentManager?.beginTransaction()?.replace(android.R.id.content, PreferencesFragment())?.commit()
}
So I'm making an app which needs to paint garland, light bulbs and other decoration. I have a code which will make an imageview on Action_Move but the app crashes. see the code below
fun drawLights(){
val listener = View.OnTouchListener(function = { view, motionEvent ->
val x = motionEvent.getX()
val y = motionEvent.getY()
when (motionEvent.action){
MotionEvent.ACTION_DOWN -> {
Toast.makeText(this,"Action Down",Toast.LENGTH_SHORT).show()
}
MotionEvent.ACTION_MOVE -> {
Toast.makeText(this, "Moving", Toast.LENGTH_SHORT).show()
////Imageview Creation Here using late init var
}
MotionEvent.ACTION_UP -> {
Toast.makeText(this,"Done" ,Toast.LENGTH_SHORT).show()
}
}
true
})
edit_Canvas.setOnTouchListener(listener)
}
Does anyone here know any blog related to this or already resolved this problem? Thanks!
You need to look for topics on drawing on the Android Canvas. There are lots of sample codes out there
This one's from the official documentation in drawing on the Canvas https://developer.android.com/training/custom-views/custom-drawing