I want to change activity(MainActivity -> MapActivity) in fragment(LookFragment) button.
LookFragment is in MainActivity FrameLayout.
This is LookFragment.kt
'''
class LookFragment : Fragment() {
lateinit var binding: FragmentLookBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentLookBinding.inflate(inflater, container, false)
binding.lookBtn.setOnClickListener {
val intent = Intent(activity, MapActivity::class.java)
startActivity(intent)
}
return binding.root
}
}
'''
When I press the button in the fragment to start Mapactivity then the app shut down.
Related
I use BottomNavigation in Android,But,After I replace RotationFragment to ScaleFragment,Back to BottomNavigationFragment,RotationViewModel's rotation value always alive
MainActivity
class MainActivity : AppCompatActivity() {
lateinit var binding : ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
val navHostFragment = supportFragmentManager
.findFragmentById(binding.navHostFragment.id) as NavHostFragment
val navController = navHostFragment.navController
val configuration = AppBarConfiguration.Builder(binding.bottomNavigationView.menu).build()
NavigationUI.setupActionBarWithNavController(this, navController,configuration)
NavigationUI.setupWithNavController(binding.bottomNavigationView, navController)
}
}
RotationFragment
When image clicking,after rotation value add 100,use animator rotation image and save (rotation+100) to ViewModel rotation value,but,after switch ScaleFragment,back to RotationFragment RotationViewModel's rotation is 100 not 0
class RotationFragment : Fragment() {
private lateinit var viewBinding : RotationFragmentBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
viewBinding = RotationFragmentBinding.inflate(inflater, container, false)
return viewBinding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val viewModel = ViewModelProvider(this).get(RotationViewModel::class.java)
//viewBinding.imgRotationMood.rotation = viewModel.rotation.toFloat()
Log.d("onViewCreated", "onViewCreated: ${viewModel.rotation.toFloat()}")
val animatorMood = ObjectAnimator.ofFloat(viewBinding.imgRotationMood, "rotation", 0.0f,0.0f)
animatorMood.duration = 500
viewBinding.imgRotationMood.setOnClickListener {
if(!animatorMood.isRunning) {
animatorMood.setFloatValues(viewBinding.imgRotationMood.rotation,
viewBinding.imgRotationMood.rotation + 100)
viewModel.rotation = viewModel.rotation + 100
animatorMood.start()
}
}
}
}
RotationViewModel
class RotationViewModel : ViewModel() {
var rotation = 0
}
I trying use official BottomNavigation Template,get same result
Can someone help me figure out how i am supposed to navigate from an item in recyclerview to this repoFragment? I want to display these things in repoFragment using the GitHub API.
I want to click the reponame in the item of the recycler view. With the onClickListener i wish to open a new fragment (RepoFragment) with the info of the clicked item from the recyclerview.
I'm doing a repository search and want to display the info when clicking on the repository.The code below represents what i tried to do.
Thank you for your help!
This is my RepositoryRecyclerAdapter:
class RepositoryRecyclerAdapter(repos: List<RepositoriesResponse>): RecyclerView.Adapter<SearchPlaceHolder>(){
private var repoList = repos
var navc: NavController?= null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchPlaceHolder {
val inflatedView = LayoutInflater.from(parent.getContext()).inflate(R.layout.pravokutnik, parent, false);
return SearchPlaceHolder(inflatedView)
}
override fun onBindViewHolder(holder: SearchPlaceHolder, position: Int) {
val repo = repoList[position]
holder.bindRepo(repo)
holder.itemView.setOnClickListener(object: View.OnClickListener{
override fun onClick(v: View){
navc?.navigate(R.id.action_searchFragment_to_repoFragment)
}
})
}
override fun getItemCount() = repoList.size
}
This is my SearchFragment:
class SearchFragment : BaseFragment<SearchViewModel, FragmentSearchBinding, SearchRepository>() {
private lateinit var mContext: Context
private var reposList = ArrayList<RepositoriesResponse>().toList()
private lateinit var adapterRepo: RepositoryRecyclerAdapter
private lateinit var linearLayoutManagerDistance: LinearLayoutManager
val args: SearchFragmentArgs by navArgs()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mContext = this.requireContext()
linearLayoutManagerDistance = LinearLayoutManager(mContext)
linearLayoutManagerDistance.orientation = LinearLayoutManager.VERTICAL
binding.repositoriesList.layoutManager = linearLayoutManagerDistance
val query = args.query
val apiInterface = RepositoryApi.create().getRepositoriesByQuery(query)
apiInterface.enqueue( object : Callback<QueryResponse> {
override fun onResponse(call: Call<QueryResponse>?, response: Response<QueryResponse>?) {
if(response?.body() != null){
reposList = response.body()!!.items
adapterRepo = RepositoryRecyclerAdapter(reposList)
binding.repositoriesList.adapter = adapterRepo
}
}
override fun onFailure(call: Call<QueryResponse>?, t: Throwable?) {
Toast.makeText(mContext, t.toString(), Toast.LENGTH_LONG).show()
}
})
}
override fun getViewModel() = SearchViewModel::class.java
override fun getFragmentBinding(
inflater: LayoutInflater,
container: ViewGroup?
) = FragmentSearchBinding.inflate(inflater, container, false)
override fun getFragmentRepository()=
SearchRepository()
}
The HomeFragment:
class HomeFragment : BaseFragment<HomeViewModel, FragmentHomeBinding, SearchRepository>() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
var mySearchView = view.findViewById<SearchView>(R.id.search_view)
var navc = Navigation.findNavController(view)
mySearchView.setIconifiedByDefault(true);
mySearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
val action = HomeFragmentDirections.actionHomeFragmentToSearchFragment2(query)
navc?.navigate(action)
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
return false
}
})
}
override fun getViewModel() = HomeViewModel::class.java
override fun getFragmentBinding(
inflater: LayoutInflater,
container: ViewGroup?
) = FragmentHomeBinding.inflate(inflater, container, false)
override fun getFragmentRepository()=
SearchRepository()
}
RepoFragment:
class RepoFragment : BaseFragment<RepoViewModel, FragmentRepoBinding, SearchRepository>(){
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_repo, container, false)
}
override fun getViewModel() = RepoViewModel::class.java
override fun getFragmentBinding(
inflater: LayoutInflater,
container: ViewGroup?
) = FragmentRepoBinding.inflate(inflater, container, false)
override fun getFragmentRepository() = SearchRepository()
}
Also, I get an error when trying to run this code; androidstudio says that i made a mistake when inflating the layout of repofragment.
Im getting an error on the second to last close brace.
Error: A 'return' expression required in a function with a block body ('{...}')
Im trying to open a Activity (TMs) from a ImageButton in my fragement (Dashboard).
class Dashboard : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_dashboard, container, false)
view.findViewById<ImageButton>(R.id.card1).setOnClickListener {
val card1 = Intent(activity, TMs::class.java)
activity?.startActivity(card1)
}
}
}
The function onCreateView does returns a View. You have inflated the View object, just return it.
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val view = inflater.inflate(R.layout.fragment_dashboard, container, false)
..code..
return view
Anyways, I do strongly recommend you to init the clickListeners and any other UI logic in onViewCreated().
So we proceed to create the fragment by steps, first we "inflate the view" which is on onCreateView(): View and then once it is created we can add UI logic (as listeners).
It would look like this:
class Dashboard : Fragment() {
private lateinit var _view: View
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_view = inflater.inflate(R.layout.fragment_dashboard, container, false)
return _view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
view.findViewById<ImageButton>(R.id.card1).setOnClickListener {
val card1 = Intent(activity, TMs::class.java)
activity?.startActivity(card1)
}
}
}
Im in a fragment1 and i want go to fragment2 if an event occurred in a class called from the fragment1. I have tried a callback of fuction: function in Class call a function in fragment1 to go in fragment but i collect this error:
Process: com.example.ilmiogioco, PID: 7992java.lang.IllegalStateException: Method addObserver must be called on the main thread
at androidx.lifecycle.LifecycleRegistry.enforceMainThreadIfNeeded(LifecycleRegistry.java:317)
at androidx.lifecycle.LifecycleRegistry.addObserver(LifecycleRegistry.java:172)
at androidx.savedstate.SavedStateRegistryController.performRestore(SavedStateRegistryController.java:61)
at androidx.navigation.NavBackStackEntry.<init>(NavBackStackEntry.java:88)
at androidx.navigation.NavBackStackEntry.<init>(NavBackStackEntry.java:73)
at androidx.navigation.NavController.navigate(NavController.java:1138)
at androidx.navigation.NavController.navigate(NavController.java:944)
at androidx.navigation.NavController.navigate(NavController.java:877)
at androidx.navigation.NavController.navigate(NavController.java:863)
at androidx.navigation.NavController.navigate(NavController.java:851)
at com.example.ilmiogioco.FullscreenFragmentSolo.follow(FullscreenFragmentSolo.kt:77)
at com.example.ilmiogioco.Solo.SpaceView.update(SpaceView.kt:276)
at com.example.ilmiogioco.Solo.SpaceView.run(SpaceView.kt:120)
at java.lang.Thread.run(Thread.java:919)
EDIT: I have fullscreenfragmentsolo (fragment1) that want in gameoverfragment (fragment2) if the class spaceview called in fullscreenfragmentsolo collect a lost game. The function follow() is called by spaceview for return in fullscreenfragmentsolo (maybe this is the thread error).
class FullscreenFragmentSolo : Fragment() {
private var spaceView: SpaceView? = null
private lateinit var backgroundMusic: MediaPlayer
private lateinit var window: Window
private var binding: FragmentFullscreenSoloBinding? = null
object size{
var x = 0
var y = 0
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
(activity as AppCompatActivity?)!!.supportActionBar!!.hide()
getActivity()?.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
val soundEffects = SoundEffects(requireContext())
soundEffects.playSound(SoundEffects.backgroundMusic)
val outMetrics = DisplayMetrics()
getActivity()?.getWindow()?.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
window = activity?.getWindow()!!
window.attributes.width
window.attributes.height
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
val display = activity?.display
display?.getRealMetrics(outMetrics)
} else {
#Suppress("DEPRECATION")
val display = activity?.windowManager?.defaultDisplay
#Suppress("DEPRECATION")
display?.getMetrics(outMetrics)
}
size.y = outMetrics.heightPixels
size.x = outMetrics.widthPixels
backgroundMusic = MediaPlayer.create(requireContext(), R.raw.background_music)
backgroundMusic.isLooping = true
backgroundMusic.start()
val fragmentBinding = FragmentFullscreenSoloBinding.inflate(inflater, container, false)
binding = fragmentBinding
fragmentBinding.root
spaceView = SpaceView(requireContext(), size, this)
return spaceView
}
fun follow(){
findNavController().navigate(R.id.action_fullscreenFragmentSolo_to_gameoverFragment)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.soloFragment = this
}
override fun onResume() {
super.onResume()
spaceView?.resume()
}
fun stopFunction() {
spaceView?.stop()
}
override fun onPause() {
super.onPause()
backgroundMusic.release()
spaceView?.pause()
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
GameoverFragment:
open class GameoverFragment : Fragment() {
private var binding: GameoverFragmentBinding? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val fragmentBinding = GameoverFragmentBinding.inflate(inflater, container, false)
binding = fragmentBinding
return fragmentBinding.root
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding?.gameoverFragment = this
}
fun Menu(){
findNavController().navigate(R.id.action_gameoverFragment_to_startFragment)
}
> override fun onDestroyView() {
> super.onDestroyView()
> binding = null }
Can you help me?
This exception is due to your code calling (through navigation) the LifecycleRegistry.addObserver from a thread other than the Main thread. You have to ensure that you call the navigation from the main thread.
Change to this in the follow() function
import android.os.Handler
import android.os.Looper
// ...
fun follow() {
Handler(Looper.getMainLooper()).post {
findNavController().navigate(R.id.action_fullscreenFragmentSolo_to_gameoverFragment)
}
}
I am very new to taking an android application and for a project I need a BottomNavigati but I cannot get my data that comes from the beginning of the session to pass to the main fragment
Activity:
val bundle1 = Bundle()
bundle1.putString("User",User)
bundle1.putString("Correo",Correo)
bundle1.putString("Region",Region)
val navView: BottomNavigationView = findViewById(R.id.nav_view)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController: NavController = navHostFragment.navController
// 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_notifications
)
)
navHostFragment.arguments = bundle1
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
HOMEFRAGMEN:
private lateinit var homeViewModel: HomeViewModel
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
homeViewModel = ViewModelProvider(this).get(HomeViewModel::class.java)
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.textView4)
return root
}
}
There is no direct access to HomeFragment from MainActivity in your case. BottomNavigation uses nested navigation architecture pattern with nested graphs.
More details here: Passing argument(s) to a nested Navigation architecture component graph
But you can use alternative way to pass data from Activity to Fragment using context.
Step 1 - Describe HomeFragmentData model:
data class HomeFragmentData(
val value: String
)
Step 2 - Describe HomeFragment interface:
interface IHomeFragment {
fun getHomeFragmentData(): HomeFragmentData
}
Step 3 - Implement interface to your Activity:
class MainActivity : AppCompatActivity(), IHomeFragment {
override fun getHomeFragmentData(): HomeFragmentData {
return HomeFragmentData(
value = "Home Fragment data"
)
}
// Rest of your code
}
Step 4 - Call function getHomeFragmentData() from HomeFragment using context:
class HomeFragment : Fragment() {
private var interactionListener: IHomeFragment? = null
override fun onAttach(context: Context) {
super.onAttach(context)
when(context) {
is IHomeFragment -> {
interactionListener = context
}
else -> throw RuntimeException("$context has to implement IHomeFragment")
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val root = inflater.inflate(R.layout.fragment_home, container, false)
val textView: TextView = root.findViewById(R.id.text_home)
interactionListener?.getHomeFragmentData().let {
textView.text = it?.value
}
return root
}
}