I want to start bounce scale animation of textview every activity's onResume. I noticed that sometimes text doesnt'show during textview scaling animation. I see only background of that textview. This bug appears only on some devices: few Xiaomi models, one Samsung, one Pixel. Works good on emulator. I am using Animator. I tried Animation class and bug still exists.How can I fix this?
My Activity code:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onResume() {
super.onResume()
playAnimation()
}
private fun playAnimation() {
val textView = findViewById<TextView>(R.id.textView)
textView.scaleX = 0f
textView.scaleY = 0f
val badgeAnimator = ValueAnimator.ofFloat(0f, 1f
).apply {
duration = 800L
interpolator = BounceInterpolator()
addUpdateListener { animation ->
val value = animation.animatedValue as Float
textView.scaleX = value
textView.scaleY = value
}
}
val animatorSet = AnimatorSet()
animatorSet.apply {
startDelay = 1500L
play(badgeAnimator)
start()
}
}
}
Activity xml:
<?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">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textColor="#color/white"
android:paddingHorizontal="10dp"
android:background="#drawable/bg_badge_count_v2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Demonstration video of this issue.
I found that if i valueanimator with start value 0.01f instead of 0f bug dissappears. That works with animation class too. I think that something in android system clears text in TextView when scaleX and scaleY are zero.
So 0.01f I think is ok, because it is not visible for user and looks the same as 0f
Related
I have a problem:
I have a TextView whose content is constantly changing via LiveData. This looks all right when the animation isn't executing, but when the MotionLayout starts executing, my text gets blocked a little bit.
And the constraints of my TextView and Button are packed.
activity:
class ErrorActivity : AppCompatActivity() {
private val mViewModel by viewModels<ErrorViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
DataBindingUtil.setContentView<ActivityErrorBinding>(this, R.layout.activity_error).apply {
lifecycleOwner = this#ErrorActivity
viewModel = mViewModel
}
}
fun startStopAnim(v: View) {
mViewModel.anim()
}
}
activity layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:binding="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="viewModel"
type="com.test.test.ErrorViewModel" />
</data>
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="#+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="#xml/scene"
binding:anim="#{viewModel.mAnim}">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{#string/test(viewModel.mCountDown)}"
android:textSize="32sp"
app:layout_constraintEnd_toStartOf="#+id/btn"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="#string/test" />
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/tv"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/anim"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="startStopAnim"
android:text="startOrStop"
android:textAllCaps="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
</layout>
viewModel:
class ErrorViewModel : ViewModel() {
private val _countDown: MutableLiveData<String> = MutableLiveData()
val mCountDown: LiveData<String> = _countDown
private val _anim: MutableLiveData<Boolean> = MutableLiveData()
val mAnim: LiveData<Boolean> = _anim
private var count = 0
private var state = false
init {
viewModelScope.launch(Dispatchers.IO) {
while (true) {
delay(1000)
_countDown.postValue(count++.toString())
}
}
}
fun anim() {
state = !state
_anim.value = state
}
}
#BindingAdapter("anim")
fun anim(layout: MotionLayout, play: Boolean?) {
play?.let {
if (it) {
layout.transitionToEnd()
} else {
layout.transitionToStart()
}
}
}
motionScene:
For simplicity, Scene has only one duration
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="#+id/end"
app:constraintSetStart="#+id/start"
app:duration="2000" />
</MotionScene>
gif
As you can see in the gif, when there is no click, everything works fine for the numbers, but when I click the button, a 2 second animation starts, during which time my text doesn't display properly.
Of course, this is just a demo example. In a real scene, not only the text is not displayed completely, but even the TextView And ImageView are misplaced, and once the animation is executed, it cannot be recovered.
Can someone help me...
Actually in a real scene, the parent layout (B) of the problematic TextView (A) would perform a displacement animation. As long as this animation is executed once, the constraint relationship of TextView A will definitely have problems and cannot be restored (onResume can be restored after onPause is currently found)
By design during animation MotionLayout does not honor requestLayout.
Because in the majority of applications it is not needed and would have a significant impact on performance.
To enable it in the transition add
<Transition ... motion:layoutDuringTransition="honorRequest" \>
everyone. I'm trying to display a line chart in a full-screen activity. Unfortunately I can't do that. I always get to see my activity_main.xml layout. I also have my LineChart in it, within a CardView. Everything works fine in this activity. But as soon as I switch to activity_details_vitali.xml via a button, I don't see a line chart, just my main_activity. I think I have a wrong binding here. However, I can't find the error
class DetailsVitali : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_details_vitali)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setLineChartData()
}
private fun setLineChartData() {
val linevalues = ArrayList<Entry>()
linevalues.add(Entry(20f, 0.0F))
linevalues.add(Entry(30f, 3.0F))
linevalues.add(Entry(40f, 2.0F))
linevalues.add(Entry(50f, 1.0F))
linevalues.add(Entry(60f, 8.0F))
linevalues.add(Entry(70f, 10.0F))
linevalues.add(Entry(80f, 1.0F))
linevalues.add(Entry(90f, 2.0F))
linevalues.add(Entry(100f, 5.0F))
linevalues.add(Entry(110f, 1.0F))
linevalues.add(Entry(120f, 20.0F))
linevalues.add(Entry(130f, 40.0F))
linevalues.add(Entry(140f, 50.0F))
val linedataset = LineDataSet(linevalues, "First")
//We add features to our chart
linedataset.color = resources.getColor(R.color.purple_200)
linedataset.circleRadius = 5f
linedataset.setDrawFilled(true)
linedataset.valueTextSize = 10F
linedataset.fillColor = resources.getColor(R.color.purple_500)
linedataset.setMode(LineDataSet.Mode.CUBIC_BEZIER);
//We connect our data to the UI Screen
val data = LineData(linedataset)
binding.getTheGraph.data = data
binding.getTheGraph.setBackgroundColor(resources.getColor(R.color.white))
binding.getTheGraph.animateXY(2000, 2000, Easing.EaseInCubic)
}
layout
<?xml version="1.0" encoding="utf-8"?>
LinearLayout 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"
android:orientation="horizontal"
tools:context=".DetailsVitali">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
app:cardCornerRadius="10dp"
android:elevation="20dp"
android:layout_gravity="center_horizontal">
<com.github.mikephil.charting.charts.LineChart
android:id="#+id/graphDetail"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.cardview.widget.CardView>
</LinearLayout>
</LinearLayout>
EDIT
And I also don't have access to the ID of my LineChart in the DetailsVitali.class. binding.ID.data = data is the ID is from the activity_main.xml.
From your comment that your desired layout is defined in activity_details_vitali.xml, you should be loading ActivityDetailsVitaliBinding, not ActivityMainBinding.
And as mentioned by #ARiF, you can remove the first call to setContentView since you are overwriting it with the second call to setContentView.
In one of the fragments of the app i'm developing, i let the users create various chips and every chip represents an option. I was able to animate the chip creation.
Now, when the user taps on a chip, i remove it from the group. I was able to associate a custom animation to the removal (see the gif) but when a "middle chip" is deleted, the chips to the right suddenly move to the left, when the animation is over.
Layout:
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="#dimen/horizontal_scroll_height"
android:scrollbars="none">
<com.google.android.material.chip.ChipGroup
android:id="#+id/rouletteChipList"
style="#style/Widget.MaterialComponents.ChipGroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="#dimen/chip_horizontal_margin"
android:paddingEnd="#dimen/chip_horizontal_margin"
app:chipSpacing="#dimen/chip_spacing"
app:singleLine="true">
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
Chip deletion:
private void removeChip(final Chip chip) {
#SuppressWarnings("ConstantConditions") final ChipGroup optionsList = getView().findViewById(R.id.ChipList);
// Remove the chip with an animation
if (chip == null) return;
final Animation animation = AnimationUtils.loadAnimation(getContext(), R.anim.chip_exit_anim);
chip.startAnimation(animation);
chip.postDelayed(new Runnable() {
#Override
public void run() {
optionsList.removeView(chip);
}
}, 400);
}
Chip layout:
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.chip.Chip xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/placeholder"
android:textAlignment="center"
app:chipBackgroundColor="#color/grayTranslucent"
app:rippleColor="?colorAccent" />
I'd like to have a smooth animation, where the chips smoothly move to the left when a "middle chip" is deleted. I tried a couple of things, but no luck.
if you mean something like this
i,ve added it inside a HSV and added android:animateLayoutChanges="true" on chip_group, see below code
<HorizontalScrollView
android:scrollbars="none"
.
>
<com.google.android.material.chip.ChipGroup
android:id="#+id/chip_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
</com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>
inside my Code i have added chips dynamically to this chip_group.
val newChip = Chip(this, null, R.attr.chipStyle)
newChip.text = "text"
newChip.isClickable = true
newChip.isFocusable = true
newChip.setOnClickListener(chipClickListener)
chip_group.addView(newChip)
and there is a onClickListener on each chip.inside it i start a fade animation and in onAnimationEnd do a removeView on chip_group
private val chipClickListener = View.OnClickListener {
val anim = AlphaAnimation(1f,0f)
anim.duration = 250
anim.setAnimationListener(object : Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {}
override fun onAnimationEnd(animation: Animation?) {
chip_group.removeView(it)
}
override fun onAnimationStart(animation: Animation?) {}
})
it.startAnimation(anim)
}
Similar to the attachment in this issue, my button's corner shadows look pretty dodgy. But with a custom edge and rounded corner treatment, the button seems to lose elevation and there is no ripple / click effect. Any idea on what I have done wrong?
Material version is 1.1.0-alpha07
class CurvedEdgeTreatment (private val size: Float) : EdgeTreatment(), Cloneable {
public override fun clone(): EdgeTreatment {
return super<EdgeTreatment>.clone()
}
override fun getEdgePath(length: Float, center: Float, interpolation: Float, shapePath: ShapePath) {
shapePath.quadToPoint(center, -size * interpolation, length, 0f)
}
}
class ButtonActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_button)
val shapeAppearanceModel = ShapeAppearanceModel().apply {
setAllCorners(RoundedCornerTreatment(12.dpToPx(resources.displayMetrics).toFloat()))
setAllEdges(CurvedEdgeTreatment(3.dpToPx(resources.displayMetrics).toFloat()))
}
val backgroundDrawable = MaterialShapeDrawable(shapeAppearanceModel).apply {
setTint(ContextCompat.getColor(this#ButtonActivity, R.color.color_secondary))
shadowCompatibilityMode = SHADOW_COMPAT_MODE_ALWAYS
elevation = 12f
setUseTintColorForShadow(true)
paintStyle = Paint.Style.FILL
}
raisedContainedButton.background = backgroundDrawable
}
fun Int.dpToPx(displayMetrics: DisplayMetrics): Int = (this * displayMetrics.density).toInt()
fun Int.pxToDp(displayMetrics: DisplayMetrics): Int = (this / displayMetrics.density).toInt()
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:gravity="center"
android:orientation="vertical">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:padding="16dp"
android:clipChildren="false"
android:clipToPadding="false">
<com.google.android.material.button.MaterialButton
android:id="#+id/raisedContainedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="I am a button la la la la la la"/>
</FrameLayout>
</LinearLayout>
In MainActivity, I have a pie chart, where the libary get from GitHub - PhilJay/MPAndroidChart: A powerful Android chart view. I add the pie chart into cardView.When cardView is clicked, toast suppose to be displayed. But the onClickListener not working at all.
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showChart()
cardView.setOnClickListener {
Toast.makeText(application,"clicked",Toast.LENGTH_LONG).show()
}
}
private fun showChart() {
chart.setUsePercentValues(true)
chart.description.isEnabled = false
chart.center
chart.extraRightOffset = 20f
chart.isDrawHoleEnabled = true
chart.setHoleColor(Color.WHITE)
chart.setTransparentCircleColor(Color.WHITE)
chart.setTransparentCircleAlpha(10)
chart.holeRadius = 58f
chart.transparentCircleRadius = 46f
chart.setDrawCenterText(true)
chart.rotationAngle = 0f
chart.isRotationEnabled = true
chart.animateY(1400, Easing.EaseInOutQuad)
val l = chart.legend
l.verticalAlignment = Legend.LegendVerticalAlignment.CENTER
l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT
l.orientation = Legend.LegendOrientation.VERTICAL
l.setDrawInside(false)
l.xOffset = 50f
chart.setEntryLabelColor(Color.WHITE)
chart.setEntryLabelTextSize(12f)
setData(3,5)
}
private fun setData(numOpen: Int, numInProgress: Int) {
val entries = ArrayList<PieEntry>()
val colors = ArrayList<Int>()
if (numOpen > 0) {
entries.add(PieEntry(numOpen.toFloat(), "Open"))
colors.add(ColorTemplate.rgb("#F44336"))
}
if (numInProgress > 0) {
entries.add(PieEntry(numInProgress.toFloat(), "Progress"))
colors.add(ColorTemplate.rgb("#2196F3"))
}
val dataSet = PieDataSet(entries, "Status")
dataSet.sliceSpace = 3f
dataSet.iconsOffset = MPPointF(0f, 40f)
dataSet.selectionShift = 5f
dataSet.colors = colors
val data = PieData(dataSet)
data.setValueFormatter(PercentFormatter(chart))
data.setValueTextSize(11f)
data.setValueTextColor(Color.WHITE)
chart.data = data
// undo all highlights
chart.highlightValues(null)
chart.invalidate()
}
}
main_activity
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp">
<com.github.mikephil.charting.charts.PieChart
android:background="#color/colorPrimary"
android:id="#+id/chart"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_gravity="center_horizontal|center_vertical"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
Image
As the PieChart fully absorbing the click to interact with the chart elements, the click listener defined in the parent will not be called. Even If you set an OnClickListener to PieChart, it won't work. The solution to this problem is to set onChartGestureListener to PieChart and call your method from onChartSingleTapped.
Example
override fun onCreate(savedInstanceState: Bundle?) {
...
cardView.setOnClickListener {
doThis();
}
chart.onChartGestureListener = object : OnChartGestureListener {
override fun onChartSingleTapped(me: MotionEvent?) {
doThis()
}
}
}
fun doThis(){
// your code goes here
}