The FloatingActionButton comes pre-configured with a 0.5dp border, which goes against Google's own Material guidelines.
You can remove the border in XML via app:borderWidth = 0dp
Is there a way to change this property programmatically?
There's no a clean way of doing it.
You can do it through reflection, with the following code (Kotlin):
val button: FloatingActionButton // your button, initialized someway
// set the field mBorderWidth of your button, it's not enough to do this because this value has already been consumed for drawing the button's background; it shouldn't be necessary, anyway set it...
val fieldBorderWidth = FloatingActionButton::class.java.getDeclaredField("mBorderWidth")
fieldBorderWidth.isAccessible = true
fieldBorderWidth.setInt(button, 0)
// the trick is to call again setBackgroundDrawable (it's already been called inside of the constructor) on the field mImpl of the FloatingActionButton; you can call it with the button's parameters but passing 0 as borderWidth. So obtain the needed button's parameters and call that method
// (since all these fields and methods are private you must set everything as accessible)
// get button's parameters
val fieldBackgroundTint = FloatingActionButton::class.java.getDeclaredField("mBackgroundTint")
fieldBackgroundTint.isAccessible = true
val fieldBackgroundTintValue = fieldBackgroundTint.get(button)
val fieldBackgroundTintMode = FloatingActionButton::class.java.getDeclaredField("mBackgroundTintMode")
fieldBackgroundTintMode.isAccessible = true
val fieldBackgroundTintModeValue = fieldBackgroundTintMode.get(button)
val fieldRippleColor = FloatingActionButton::class.java.getDeclaredField("mRippleColor")
fieldRippleColor.isAccessible = true
val fieldRippleColorValue = fieldRippleColor.get(button)
// get button's mImpl field
val methodGetImpl = FloatingActionButton::class.java.getDeclaredMethod("getImpl")
methodGetImpl.isAccessible = true
val fieldImplValue = methodGetImpl.invoke(button)
// get mImpl's setBackgroundDrawable method and call it
val methodSetBackgroundDrawable = fieldImplValue.javaClass.getDeclaredMethod("setBackgroundDrawable", ColorStateList::class.java, PorterDuff.Mode::class.java, Int::class.java, Int::class.java)
methodSetBackgroundDrawable.isAccessible = true
methodSetBackgroundDrawable.invoke(fieldImplValue, fieldBackgroundTintValue, fieldBackgroundTintModeValue, fieldRippleColorValue, 0)
Related
I tried to show a random imageView out of 2(one,two) with this
binding.imageView.setImageResource(oneandtwo[random.nextInt(oneandtwo.size)]) it works fine
and
i wanted to increase score when i clicked on imageView
but score increases independent to that, sometimes increases when i clicked on imageView2 and sometimes imageView, i want to increase score when i only clicked on imageView. i couldnt figure out. Thanks in advance.
var score = 0
val oneandtwo: IntArray = intArrayOf(
R.drawable.ic_baseline_looks_one_24,
R.drawable.ic_baseline_looks_two_24
)
binding.imageView.setOnClickListener{
val random = Random
binding.imageView.setImageResource(oneandtwo[random.nextInt(oneandtwo.size)])
if (oneandtwo[random.nextInt(oneandtwo.size)]==(R.drawable.ic_baseline_looks_one_24)){
score++
binding.textView.text = score.toString()
}
}
The number you gave in the image and the number you checked in the if block may not match and will not give the result you want. If you change code like this. Probably your problem will be solved.
binding.imageView.setOnClickListener{
val random = Random().nextInt(oneandtwo.size)
binding.imageView.setImageResource(oneandtwo[random])
if (oneandtwo[random]==(R.drawable.ic_baseline_looks_one_24)){
score++
binding.textView.text = score.toString()
}
}
What you are doing is checking the resourceId of the newly generated image, not the one you just clicked. That's why it not giving the result you want ,i.e, increment on the click of imageView and not on click of imageView2. Try below code. it should work
var score = 0
val oneandtwo: IntArray = intArrayOf(R.drawable.ic_baseline_looks_one_24,R.drawable.ic_baseline_looks_two_24)
/*Initalize the initial image and tag either here or in xml file*/
val random = Random().nextInt(oneandtwo.size)
binding.imageView.setImageResource(oneandtwo[random])
binding.imageView.Tag = oneandtwo[random]
binding.imageView.setOnClickListener{
val imageTag = binding.imageView.Tag
if (imageTag == (R.drawable.ic_baseline_looks_one_24)) {
score++
binding.textView.text = score.toString()
}
val random = Random().nextInt(oneandtwo.size)
binding.imageView.setImageResource(oneandtwo[random])
binding.imageView.Tag = oneandtwo[random]
}
You've got two problems that both the answers cover - if clicking a particular image is meant to give you points, you have to check the image before you change it. And if you're using random items, you need to pick one and keep a reference to it. This:
binding.imageView.setImageResource(oneandtwo[random.nextInt(oneandtwo.size)])
if (oneandtwo[random.nextInt(oneandtwo.size)]==(R.drawable.ic_baseline_looks_one_24))
picks two completely independent numbers which may not match - and they're supposed to be referencing the same item, right? Get your random thing once, use it twice
RahulK's answer should work but here's another way you could do it, with an explicit listener object so you can throw a state variable in there:
binding.imageView.setOnClickListener(object : View.OnClickListener {
// keep track of whether the current image adds to the score when clicked
var givesPoints = false
override fun onClick(view: View) {
// first, we just got clicked, so add to the score if appropriate
if (givesPoints) score++
// you can just call random() on a collection to get a random element from it
val resId = oneAndTwo.random()
// set the image - might be better to do (view as ImageView).setImageResource
// so it sets it on -whatever was clicked- so it's easier to reuse
binding.imageView.setImageResource(resId)
// now set whether this new image gives points or not
givesPoints = resId == R.drawable.ic_baseline_looks_one_24
}
})
So this way, every time you set a new image, the listener knows whether to give points for it next time it's clicked
I don't know how you have this set up, you're only initialising things when the image is clicked so if you need to set them up beforehand (so you can have an image displayed that you an click for points) you probably want everything in a separate function you can call when clicked and during setup:
/** Assigns a random picture to this ImageView - returns true if it's a point-scoring pic */
fun assignRandomPic(imageView: Imageview): Boolean {
val resId = oneAndTwo.random()
imageView.setImageResource(resId)
return resId == R.drawable.ic_baseline_looks_one_24
}
// set an initial image, storing whether it scores points
val scoreMe = assignRandomPic(binding.imageView)
binding.imageView.setOnClickListener(object : View.OnClickListener {
// initialise this as appropriate for the image we just set up
var givesPoints = scoreMe
override fun onClick(view: View) {
if (givesPoints) score++
// set a new pic and store its point-scoring state
givesPoints = assignRandomPic(view as ImageView)
}
})
or you could just do var givesPoints = assignRandomPic(binding.imageView) and init the image inside the click listener, whatever feels better
I need to add views to LinearLayout dynamically on POST request finished inside a fragment.
Here is my function that creates and setups the view and returns it, then I add it to the chatsRoot via addView() method. No exceptions, but views are not added.
After some debug I noticed, that in logcat there is only one message "Banner created1" and no message "Banner created2", like if the program freezed on loading the color resource.
Log.d("VIEW", "Banner created1") // appears in logcat
val colorFrom = resources.getColor(R.color.banner_regular, null)
Log.d("VIEW", "Banner created2") // not appears in logcat
private fun generateBanner(chatData: ChatData):View? {
val banner = inflater.inflate(R.layout.chat_banner, null, false)
banner.run {
findViewById<TextView>(R.id.user_name).text = chatData.name
findViewById<TextView>(R.id.short_code).text = chatData.shortCode
findViewById<TextView>(R.id.short_message).text =
chatData.lastMessage.let { it.substring(0, min(40, it.length)) + "..." }
findViewById<ImageView>(R.id.unread_dot).visibility =
if (chatData.hasUnread) VISIBLE else GONE
findViewById<TextView>(R.id.date_time_text).text = chatData.lastMessageTime
}
Log.d("VIEW", "Banner created1")
val colorFrom = resources.getColor(R.color.banner_regular, null)
Log.d("VIEW", "Banner created2")
val colorTo = resources.getColor(R.color.banner_clicked, null)
val animation = ValueAnimator.ofObject(
ArgbEvaluator(), colorFrom, colorTo, colorFrom
).apply {
addUpdateListener {
banner.setBackgroundColor(animatedValue as Int)
}
}
banner.setOnClickListener {
animation.start()
openChat(chatData.uid)
}
return banner
}
generateBanner() is called here, same situation: top is printed, bottom is not
private fun addChatsToRoot(chats:List<ChatData>) {
Log.d("VIEW", "Adding chats to root") // printed to logcat
for(chatData in chats) {
chatsData += chatData.uid to chatData
val banner = generateBanner(chatData)
chatsRoot.addView(banner)
}
Log.d("VIEW", "Chats are added to the layout") // not in logcat
}
I tried removing null parameter for the theme, nothing changed.
I also changed resources call to raw number representing white colors, layout created, nothing freezed the code, but layout inflated wrongly, banner.height is always zero, even if in its drawable file I set minHeight.
So it looks like I just cant load any kind of a resource from this fragment
Try this
ContextCompat.getColor(applicationContext,R.color.banner_regular)
Turned out all the problems were because I had a fragment inside another fragment. This caused problems not only with resource access, but also with inflating additional layout views.
My solution is to move fragments to one level and navigate using one navController
I have a simple button in my recyclerview, when clicked the first time it should make the text editable, when clicked the second time, it should confirm the change. The problem I'm having is that I have the two onClickListeners set up, but they refer to each other, and the bottom one can always resolve the top one, but the top one can't resolve the bottom one.
Recyclerview: bindIngredient
fun bindIngredient(ingredient: ListIngredientsQuery.Item, clickListener: RecyclerViewClickListener) {
val ocl1 = View.OnClickListener{
//Text Editable
view.ingEditText.setText(view.ingNameTV.text.toString())
view.ingNameTV.visibility = View.GONE
view.ingEditText.visibility = View.VISIBLE
view.ingEditButton.text = "Confirm"
view.ingEditButton.setOnClickListener(ocl2)
}
var ocl2 = View.OnClickListener {
//Text Not Editable
view.ingNameTV.text = view.ingEditText.text
view.ingEditText.visibility = View.GONE
view.ingNameTV.visibility = View.VISIBLE
view.ingEditButton.setOnClickListener(ocl1)
clickListener.onConfirmSelect(ingredient)
}
this.ingredient = ingredient
view.ingNameTV.text = ingredient.name()
view.ingEditButton.setOnClickListener(ocl1)
view.veganSpinner.setSelection(Vegan.valueOf(ingredient.vegan().toString()).ordinal, false)
view.gfSpinner.setSelection(GlutenFree.valueOf(ingredient.glutenfree().toString()).ordinal, false)
}
In this example the line
view.ingEditButton.setOnClickListener(ocl2)
errors because ocl2 is unresolved. If I switch the order of the two onClickListeners being declared and initialized, the line
view.ingEditButton.setOnClickListener(ocl1)
errors because ocl1 is resolved. I take this to mean that it won't look further down to find what it needs, it'll only rely on objects that have already been initialized.
Is there a way to fix this? Is there a better way to do this? I'm tempted to just put two buttons in the same spot, give them each their own onclicklistener and swap their visibility, but this seems like a waste of resources.
You need to declare your objects before you use them.
fun bindIngredient(ingredient: ListIngredientsQuery.Item, clickListener: RecyclerViewClickListener) {
val ocl1: View.OnClickListener
val ocl2: View.OnClickListener
ocl1 = View.OnClickListener{
//Text Editable
view.ingEditText.setText(view.ingNameTV.text.toString())
view.ingNameTV.visibility = View.GONE
view.ingEditText.visibility = View.VISIBLE
view.ingEditButton.text = "Confirm"
view.ingEditButton.setOnClickListener(ocl2)
}
ocl2 = View.OnClickListener {
//Text Not Editable
view.ingNameTV.text = view.ingEditText.text
view.ingEditText.visibility = View.GONE
view.ingNameTV.visibility = View.VISIBLE
view.ingEditButton.setOnClickListener(ocl1)
clickListener.onConfirmSelect(ingredient)
}
this.ingredient = ingredient
view.ingNameTV.text = ingredient.name()
view.ingEditButton.setOnClickListener(ocl1)
view.veganSpinner.setSelection(Vegan.valueOf(ingredient.vegan().toString()).ordinal, false)
view.gfSpinner.setSelection(GlutenFree.valueOf(ingredient.glutenfree().toString()).ordinal, false)
}
However, it would be better if you just used one OnClickListener. You can simply save which state you are in, and when the button is clicked, you just check which state you are in, perform your action, and then change the state. This way you don't have to worry about switching your listeners, which can get messy.
I have an AuthorizationActivity with 3 scenes, which are simply different number of fields, so when user comes on Activity runs first "splash scene", with 2 buttons(Sign In, Sign Up), by clicking on each user sees the same activity but different scenes. By clicking on Back button I change scene, for example if user on the Sign In, back click -> change scene to splash.
And now I have a problem, when he at first time went to Sign In, typing text(validation works,logic works, all is cool), then he decides go back, and go again to SignIn (logic is broken, validation doesn't work, things are bad)
Memory is growing, so I guess the problem is a multiple objects of scenes, because if I on SignIn and all fields filled correctly debug shows that my model is empty. I appreciate any help)
go SignUp
fun goSignUpTransition(v: View) {
TransitionManager.beginDelayedTransition(rootContainer_AS, changeBounds)
back.isClickable = true
splashSceneFields.sceneRoot.visibility = View.GONE
val layoutParams = innerArcContainer_SSM.layoutParams
layoutParams.height = signUpHeaderHeight
innerArcContainer_SSM.layoutParams = layoutParams
val pp = localRoot.layoutParams as LinearLayout.LayoutParams
pp.topMargin = signUpMargin
this.signUpContainer.visibility = View.VISIBLE
this.signUpContainer.animate().alpha(1f).start()
this.wellaLogo_SA.visibility = View.GONE
this.wellaLogo_SA.animate().alpha(0f).start()
this.title_SSM.text = getString(R.string.sign_up_text)
val alpha = this.toolbarControllers_SSM.animate().alpha(1f)
alpha.duration = ANIM_DURATION
alpha.start()
TransitionManager.go(signUpScene)
splashSceneFields.sceneRoot.visibility = View.VISIBLE
}
go back
fun goSplashTransition(v: View) {
galleryBottomSheet.photoURI = null
userPhoto_SSM.setImageResource(R.drawable.ic_photo_upload_white_big)
TransitionManager.beginDelayedTransition(rootContainer_AS, changeBounds)
splashSceneFields.sceneRoot.visibility = View.GONE
val layoutParams = innerArcContainer_SSM.layoutParams
layoutParams.height = preAnimDimension
innerArcContainer_SSM.layoutParams = layoutParams
val pp = localRoot.layoutParams as LinearLayout.LayoutParams
pp.topMargin = 0
val animator = wellaLogo_SA.animate()
animator.scaleX(1f).scaleY(1f).duration = ANIM_DURATION
animator.start()
val alpha = this.toolbarControllers_SSM.animate().alpha(0f)
alpha.duration = ANIM_DURATION
alpha.start()
this.signUpContainer.animate().alpha(0f).start()
this.signUpContainer.visibility = View.GONE
this.wellaLogo_SA.visibility = View.VISIBLE
this.wellaLogo_SA.animate().alpha(1f).start()
TransitionManager.go(splashSceneFields)
back.isClickable = false
splashSceneFields.sceneRoot.visibility = View.VISIBLE
}
Found solution by myself, every time when scenes comes, I had to find all my views again, set listeners and so on. Scene has a setEnterAction where you'd like to bind UI or update your model(this I supposed to do) and setExitAction if you have something you have to release/clear/update, do it there.
I am changing EditText visibility from invisible to visible by using setvisibility(View.INVISIBLE) and setvisibility(View.VISIBLE). But i also want to know is there any method provided in android to check EditText's visibility i.e is EditText is visible or any of that kind.
Thanks in advance.
You should be able to retrieve that by calling the method isShown() on your EditText.
you can try this way also ...
if(edittextname.getVisibility() == View.VISIBLE)
{
}
or
if(edittextname.getVisibility() == View.INVISIBLE)
{
}
Try to use this method:
isShown();
Kotlin approach -
val editText = findViewById<EditText>(R.id.editText)
if(editText.isVisible(){
// do your stuff
}
Method -
fun View.isVisible() = this.visibility == View.VISIBLE // check if view is visible
fun View.isNotVisible() = !this.isVisible()
fun View.beVisible() = this.visibility = View.VISIBLE // sets view visible
fun View.beGone() = this.visibility = View.GONE. // sets view gone