I am trying to add when or if statement to my code. for example, once I press the first/second button it will change the colors of button,button2 to red. and if I just press the button3 it will become green. If there is also a way more easy method I am looking for it.
`binding.button.isSelected
binding.button.setOnClickListener {
binding.button.setBackgroundColor(R.drawable.red)
}
binding.button2.isSelected
binding.button2.setOnClickListener {
binding.button2.setBackgroundColor(R.drawable.red)
}
binding.button3.isSelected
binding.button3.setOnClickListener {
binding.button3.setBackgroundColor(R.drawable.green)
}`
EDIT
I did figure out thanks to #Tonnie, I had to change a few lines to work it as I intended. this is the code;
var isRedButtonsClicked = true
var isGreenButtonClicked = true
fun colorButtonsRed() {
binding.button.setBackgroundColor(R.color.red)
binding.button2.setBackgroundColor(R.color.red)
}
fun colorButtonGreen() {
binding.button3.setBackgroundColor(R.color.green)
}
binding.button.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtonsRed()
}
}
binding.button2.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtonsRed()
}
}
binding.button3.setOnClickListener {
when (isGreenButtonClicked) {
true -> colorButtonGreen()
}
}
setContentView(binding.root)
I get you, you need the Buttons to work simultaneously.
In this case try to build onto this code to suit your needs.
First create a var which I name isRedButtonsSelected to monitor
Button States.
Add 2 functions to switch colors btw Green/Red and Gray (or any
color you choose)
Add 3 onClickListeners to change button Colors
The code
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var isRedButtonsClicked = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
binding.button.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtons()
false -> unColorButtons()
}
}
binding.button2.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtons()
false -> unColorButtons()
}
}
binding.button3.setOnClickListener {
when (isRedButtonsClicked) {
true -> colorButtons()
false -> unColorButtons()
}
}
setContentView(binding.root)
}
private fun colorButtons() {
binding.button.setBackgroundColor(Color.GRAY)
binding.button2.setBackgroundColor(Color.GRAY)
binding.button3.setBackgroundColor(Color.GREEN)
isRedButtonsClicked = false
}
private fun unColorButtons() {
binding.button.setBackgroundColor(Color.RED)
binding.button2.setBackgroundColor(Color.RED)
binding.button3.setBackgroundColor(Color.GRAY)
isRedButtonsClicked = true
}
}
#Gabe Sechan is right. You should use setBackgroundColor() with a Color Constant.
I am not sure what isSelected is intended to do but this code should work.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityMainBinding.inflate(layoutInflater)
binding.button.setOnClickListener {
binding.button.setBackgroundColor(Color.RED)
}
binding.button2.setOnClickListener {
binding.button2.setBackgroundColor(Color.RED)
}
binding.button3.setOnClickListener {
binding.button3.setBackgroundColor(Color.GREEN)
}
setContentView(binding.root)
}
Related
I'm using DataStore to hold a boolean and depending on the value the view will change. The value does change and works sort of, it is just the app requires a restart for the change to take. Is this because of the runBlocking?
This is the suspend fun I'm calling
suspend fun isOnBoardingCompleted(): Boolean {
return context
.dataStore
.data
.map { preferences -> preferences[ON_BOARDING_COMPLETED] ?: false }
.first()
}
class MainActivity : ComponentActivity() {
private val projectViewModel: ProjectRoomViewModel by viewModels()
#OptIn(ExperimentalPagerApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val projectRoomViewModel: ProjectRoomViewModel by viewModels()
setContent {
val preferences = DataStoreViewModel(this)
val isOnBoardingCompleted = remember {
mutableStateOf(
runBlocking {
preferences.isOnBoardingCompleted()
}
)
}
AppTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
if (isOnBoardingCompleted.value) {
RootScreen( preferences = preferences, projectRoomViewModel = projectRoomViewModel)
} else {
PagerView(navController = rememberNavController()) {
mutableStateOf(
runBlocking{
preferences.disableOnboarding()
}
)
}
}
}
}
}
}
}
I want to change the text that's appearing on the button each time I click it, so I have written the following code, but it's not working. Where am I going wrong?
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
var i=0;
Button(onClick = {i++ }) {
Text("Clicked $i times") //!!not updating here
}
}
}
}
Check how compose works with states and recomposition.
Use something like:
var i by remember { mutableStateOf(0) }
Button(onClick = {i++ }) {
Text("Clicked $i times")
}
I have read the Android official artical.
I see that MutableStateFlow is hot Flow and is observed by Compose to trigger recomposition when they change.
The Code A is from the the Android official artical, it's OK.
I'm very stranger why the author need to invoke collect to get latest value for Compose UI in Code A.
I think the Compose UI can always get the latest value of latestNewsViewModel.uiState, why can't I use Code B do the the same work?
Code A
class LatestNewsActivity : AppCompatActivity() {
private val latestNewsViewModel = // getViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
...
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
latestNewsViewModel.uiState.collect { uiState ->
when (uiState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
}
}
}
}
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
.collect { favoriteNews ->
_uiState.value = LatestNewsUiState.Success(favoriteNews)
}
}
}
}
Code B
class LatestNewsActivity : ComponentActivity() {
private val latestNewsViewModel = // getViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SoundMeterTheme {
Surface(color = MaterialTheme.colors.background) {
Greeting(latestNewsViewModel)
}
}
}
}
}
#Composable
fun Greeting(latestNewsViewModel: LatestNewsViewModel) {
val myUIState by remember{ latestNewsViewModel.uiState }
when (myUIState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
//The same
Add Content
To RaBaKa 78: Thanks!
By your opinion, can I use Code C instead of Code A?
Code C
class LatestNewsActivity : ComponentActivity() {
private val latestNewsViewModel = // getViewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SoundMeterTheme {
Surface(color = MaterialTheme.colors.background) {
Greeting(latestNewsViewModel)
}
}
}
}
}
#Composable
fun Greeting(latestNewsViewModel: LatestNewsViewModel) {
val myUIState by remember{ latestNewsViewModel.uiState.collectAsState() }
when (myUIState) {
is LatestNewsUiState.Success -> showFavoriteNews(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception)
}
}
//The same
Compose need State not StateFlow to recompose accordingly,
you can easily convert StateFlow to State in compose
val myUiState = latestNewsViewModel.uiState.collectAsState()
There is no need of using a remember {} because your StateFlow is from your viewModel, so it can manage the recomposition without remember
So like CODE B you can manually check the state of the StateFLow or convert to State and automatically recompose when the state changes.
The Code A is XML way of doing things where you can call other functions but in Compose you should do that steps in your viewModel
CODE D
class LatestNewsViewModel(
private val newsRepository: NewsRepository
) : ViewModel() {
private val _uiState = MutableStateFlow(LatestNewsUiState.Success(emptyList()))
val uiState: StateFlow<LatestNewsUiState> = _uiState
init {
viewModelScope.launch {
newsRepository.favoriteLatestNews
.collect { favoriteNews ->
_uiState.value = LatestNewsUiState.Success(favoriteNews)
}
}
}
}
#Composable
fun Greeting(latestNewsViewModel: LatestNewsViewModel) {
val myUIState = latestNewsViewModel.uiState.collectAsState()
Column(modifier = Modifier.fillMaxSIze()) {
when(myUIState) {
is LatestNewsUiState.Success -> SuccessComposable(uiState.news)
is LatestNewsUiState.Error -> showError(uiState.exception) -> ErrorComposable(uiState.exception)
}
}
}
I cannot collect any state from the same Jetpack Compose screen(JCScreen), after having it wrapped in a NavHost.
The original working solution:
this JcScreen is for user sign in
the activity ActAuth
#AndroidEntryPoint
class ActAuth : AppCompatActivity() {
private val viewModel: ViewModelAuth by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ThemeBasicHRLQ {
ScreenSignInWithInputValidationDebounce()
}
}
// to collect the state `stateSignIn`,
// and it works fine
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.stateAuth.collect { state ->
...
}
}
}
}
}
the digest of the JCScreen ScreenSignInWithInputValidationDebounce():
#OptIn(ExperimentalComposeUiApi::class, kInternalCoroutinesApi::class)
#Composable
fun ScreenSignInWithInputValidationDebounce(
viewModel: ViewModelAuth = hiltViewModel()
){
....
val stateSignIn by viewModel.stateAuth.collectAsState()
...
}
Everything works fine until I consolidating highly similar JCScreen for user sign up.
#AndroidEntryPoint
class ActAuth : AppCompatActivity() {
private val viewModel: ViewModelAuth by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ThemeBasicHRLQ {
// the new JCScreen
ScreenAuth()
}
}
// to collect the state `stateSignIn`
// but, with the new JCScreen, it does not work any more
lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.stateAuth.collect { state ->
...
}
}
}
}
}
#Composable
fun ScreenAuth() {
val navController = rememberNavController()
NavHostAuth(navController = navController)
}
#Composable
fun NavHostAuth(
navController: NavHostController,
) {
NavHost(
navController = navController,
startDestination = NavRoutesAuth.SignIn.route
) {
// I am still in this same JCScreen,
// without using the `navController`
composable(NavRoutesAuth.SignIn.route) {
ScreenSignInWithInputValidationDebounce(navController)
}
composable(NavRoutesAuth.SignUp.route) {
ScreenSignUpWithInputValidationDebounce(navController)
}
}
}
enum class NavRoutesAuth(val route: String) {
SignIn("auth/signin"),
SignUp("auth/signup"),
}
It looks to me that once wrapped into a NavHost, the state management is different.
Here may be a similar problem, with which, however, I still cannot solve my problem above.
I have a problem that drives me crazy. I try to populate Firestore db with some tests fields. First time when i tried it worked perfectly, i did some modifications and nothing seems to work right now. The problem is that set/add are never called whatever i do. I can create and log in without problems. I don't post layout because is self explanatory. A button that set data: add_ddb. Thanks.
class StartingActivity : AppCompatActivity() {
private lateinit var firebaseFirestore: FirebaseFirestore
private val firebaseAuth by lazy { FirebaseAuth.getInstance() }
private var uid = firebaseAuth.currentUser?.uid
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_starting)
firebaseFirestore = FirebaseFirestore.getInstance()
setSupportActionBar(toolbar)
supportActionBar?.apply {
setDisplayHomeAsUpEnabled(true)
setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp)
}
add_ddb.setOnClickListener {vieew->
val detail = mutableMapOf<String, Any>()
detail.put("nameOfDocument","sdsad")
detail.put("documentNumber","sdasdvc")
firebaseFirestore.collection("users").document("asda").
set(detail).addOnSuccessListener {
Toast.makeText(this,"sdasdasdasda",Toast.LENGTH_SHORT).show()
}.addOnFailureListener {
Toast.makeText(this,it.toString(),Toast.LENGTH_SHORT).show()
}
}
nav_view.apply {
setNavigationItemSelectedListener {
it.isChecked = true
drawer_layout.closeDrawers()
when (it.itemId) {
R.id.nav_signOut -> {
signOut()
true
}
else -> false
}
}
}
recycler.apply {
layoutManager = LinearLayoutManager(applicationContext)
}
DisplayInRecycler(this).displayDetails(recycler)
fab.setOnClickListener {
startActivity(intentFor<ActivityAdd>())
}
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
return when (item?.itemId) {
android.R.id.home -> {
drawer_layout.openDrawer(Gravity.START)
true
}
else -> super.onOptionsItemSelected(item)
}
}
fun signOut(){
FirebaseAuth.getInstance().signOut()
startActivity(intentFor<SignInActivity>().clearTop().clearTask())
finish()
}
}