MDC Button MaterialShapeDrawable strange shadows and no ripple - android

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>

Related

View has extra pixels when rounding corners

I have some missunderstading why this is happening. I have a parent FrameLayout that has rounded corners, and a TextView with bottom rounded corners. Corner raduses are equal, but on the screen displaying some extra pixels.
I got the same behavior with default xml rounding, and i would like to receive right work of rounded corners with not affect of parent view.
Custom text View
class SampleTextView #JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet? = null,
defStyleAttr: Int = 0
) : AppCompatTextView(context, attributeSet, defStyleAttr) {
private val cornerRadius: Float = 20f
init {
outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val left = 0
val top = 0
val right = view.width
val bottom = view.height
outline.setRoundRect(
left,
(top - cornerRadius).toInt(),
right,
bottom,
cornerRadius
)
}
}
clipToOutline = true
}
}
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"
android:background="#color/black"
tools:context=".MainActivity">
<FrameLayout
android:id="#+id/fl"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.example.testproject.SampleTextView
android:id="#+id/child"
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="bottom"
android:background="#color/black"
android:text="Some text text"
android:textColor="#color/white" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Activity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val parent = findViewById<FrameLayout>(R.id.fl)
parent.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
val left = 0
val top = 0
val right = view.width
val bottom = view.height
outline.setRoundRect(left, top, right, bottom, 20.toFloat())
}
}
parent.clipToOutline = true
}
}
Strange behavior

Exoplayer seekbar preview

I'm trying to add a preview to my seekbar on my exoplayer just like in youtube or plex (see the image below)
I've found this library but it isn't up-to-date yet.
I already have the image per frame but I don't know how to integrate them in my Exoplayer, I'm looking for either a tutorial or explanation where I should begin because I'm kind of lost there.
I've found Timebar.onScrubListener while browsing the exoplayer doc. I'm guessing I'll be using these 3 listeners to fetch the position of the scrub and display the corresponding image.
UPDATE: The library is up-to-date as of May 2020 so you can use it directly.
I'll leave code below for those who don't want to use the library.
After searching and adapting it to my needs I found a way by looking at how previewSeekBar was doing and I ended up using the same thing so here it is:
My sprite is composed of 10 columns and 6 rows, each square represent 1 second
GlideTransformation
private const val MAX_LINES = 6
private const val MAX_COLUMNS = 10
private const val THUMBNAILS_EACH = 1000 // milliseconds
private const val ONE_MINUTE = 60000 // one minute in millisecond
class GlideThumbnailTransformation(position: Long) : BitmapTransformation() {
private val x: Int
private val y: Int
init {
// Remainder of position on one minute because we just need to know which square of the current miniature
val square = position.rem(ONE_MINUTE).toInt() / THUMBNAILS_EACH
y = square / MAX_COLUMNS
x = square % MAX_COLUMNS
}
override fun transform(pool: BitmapPool, toTransform: Bitmap, outWidth: Int, outHeight: Int): Bitmap {
val width = toTransform.width / MAX_COLUMNS
val height = toTransform.height / MAX_LINES
return Bitmap.createBitmap(toTransform, x * width, y * height, width, height)
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
val data: ByteArray = ByteBuffer.allocate(8).putInt(x).putInt(y).array()
messageDigest.update(data)
}
override fun hashCode(): Int {
return (x.toString() + y.toString()).hashCode()
}
override fun equals(other: Any?): Boolean {
if (other !is GlideThumbnailTransformation) {
return false
}
return other.x == x && other.y == y
}
}
Activity
val thumbnailUrl = "https://bitdash-a.akamaihd.net/content/MI201109210084_1/thumbnails/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.jpg"
exo_progress.addListener(object : TimeBar.OnScrubListener {
override fun onScrubMove(timeBar: TimeBar, position: Long) {
previewFrameLayout.visibility = View.VISIBLE
val targetX = updatePreviewX(position.toInt(), exoPlayer.duration.toInt())
previewFrameLayout.x = targetX.toFloat()
GlideApp.with(scrubbingPreview)
.load(thumbnailUrl)
.override(Target.SIZE_ORIGINAL,Target.SIZE_ORIGINAL)
.transform(GlideThumbnailTransformation(position))
.diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.into(scrubbingPreview)
}
override fun onScrubStop(timeBar: TimeBar, position: Long, canceled: Boolean) {
previewFrameLayout.visibility = View.INVISIBLE
}
override fun onScrubStart(timeBar: TimeBar, position: Long) {}
})
private fun updatePreviewX(progress: Int, max: Int): Int {
if (max == 0) { return 0 }
val parent = previewFrameLayout.parent as ViewGroup
val layoutParams = previewFrameLayout.layoutParams as MarginLayoutParams
val offset = progress.toFloat() / max
val minimumX: Int = previewFrameLayout.left
val maximumX = (parent.width - parent.paddingRight - layoutParams.rightMargin)
// We remove the padding of the scrubbing, if you have a custom size juste use dimen to calculate this
val previewPaddingRadius: Int = dpToPx(resources.displayMetrics, DefaultTimeBar.DEFAULT_SCRUBBER_DRAGGED_SIZE_DP).div(2)
val previewLeftX = (exo_progress as View).left.toFloat()
val previewRightX = (exo_progress as View).right.toFloat()
val previewSeekBarStartX: Float = previewLeftX + previewPaddingRadius
val previewSeekBarEndX: Float = previewRightX - previewPaddingRadius
val currentX = (previewSeekBarStartX + (previewSeekBarEndX - previewSeekBarStartX) * offset)
val startX: Float = currentX - previewFrameLayout.width / 2f
val endX: Float = startX + previewFrameLayout.width
// Clamp the moves
return if (startX >= minimumX && endX <= maximumX) {
startX.toInt()
} else if (startX < minimumX) {
minimumX
} else {
maximumX - previewFrameLayout.width
}
}
private fun dpToPx(displayMetrics: DisplayMetrics, dps: Int): Int {
return (dps * displayMetrics.density).toInt()
}
XML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_gravity="bottom"
android:layoutDirection="ltr"
android:background="#CC000000"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="4dp"
android:orientation="horizontal"
android:id="#+id/controlsLayout"
app:layout_constraintBottom_toBottomOf="parent">
<ImageButton android:id="#id/exo_prev"
style="#style/ExoMediaButton.Previous"/>
<ImageButton android:id="#id/exo_rew"
style="#style/ExoMediaButton.Rewind"/>
<ImageButton android:id="#id/exo_repeat_toggle"
style="#style/ExoMediaButton"/>
<ImageButton android:id="#id/exo_play"
style="#style/ExoMediaButton.Play"/>
<ImageButton android:id="#id/exo_pause"
style="#style/ExoMediaButton.Pause"/>
<ImageButton android:id="#id/exo_ffwd"
style="#style/ExoMediaButton.FastForward"/>
<ImageButton android:id="#id/exo_next"
style="#style/ExoMediaButton.Next"/>
</LinearLayout>
<TextView android:id="#id/exo_position"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="bold"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:includeFontPadding="false"
android:textColor="#FFBEBEBE"
app:layout_constraintBottom_toTopOf="#id/controlsLayout"
app:layout_constraintStart_toStartOf="parent"/>
<FrameLayout
android:id="#+id/previewFrameLayout"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:background="#drawable/video_frame"
android:padding="2dp"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="#+id/exo_progress"
app:layout_constraintDimensionRatio="16:9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintWidth_default="percent"
app:layout_constraintWidth_percent="0.25"
tools:visibility="visible">
<ImageView
android:id="#+id/scrubbingPreview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY" />
</FrameLayout>
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="#id/exo_progress"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="26dp"
app:layout_constraintBottom_toBottomOf="#id/exo_position"
app:layout_constraintEnd_toStartOf="#id/exo_duration"
app:layout_constraintStart_toEndOf="#+id/exo_position"
app:layout_constraintTop_toTopOf="#+id/exo_position"/>
<TextView android:id="#id/exo_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14sp"
android:textStyle="bold"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:includeFontPadding="false"
android:textColor="#FFBEBEBE"
app:layout_constraintBaseline_toBaselineOf="#id/exo_position"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
drawable/video_frame
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="2dp"
android:color="#android:color/white" />
<solid android:color="#android:color/black" />
</shape>
there might be some improvement to make so feel free to comment

The image does not appear - Android

I wrote this code using recyclerview and I got the image that I got from the url why, my picture didn't appear
this is my activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="#layout/item_hero"
/>
</RelativeLayout>
this is my tools:listitem
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<ImageView
android:id="#+id/imgHeroes"
android:layout_width="80dp"
android:layout_height="80dp"
android:scaleType="centerCrop"/>
<TextView
android:id="#+id/txtHeroName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="16dp" />
</LinearLayout>
this is my MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val listHeroes = listOf(
Hero(
name = "Thor",
image = "https://media.skyegrid.id/wp-content/uploads/2019/06/Thor-4-1.jpg"
),
Hero(
name = "Captain America",
image = "https://i.annihil.us/u/prod/marvel/i/mg/1/c0/537ba2bfd6bab/standard_xlarge.jpg"
),
Hero(
name = "Iron Man",
image = "https://i.annihil.us/u/prod/marvel/i/mg/6/a0/55b6a25e654e6/standard_xlarge.jpg"
)
)
val heroesAdapter = HeroAdapter(listHeroes) {hero ->
Toast.makeText(this, "hero clicked ${hero.name}", Toast.LENGTH_SHORT).show()
}
rvMain.apply {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = heroesAdapter
}
}
}
this is my adapter
class HeroAdapter(
private val heroes: List<Hero>,
private val adapterOnclick: (Hero) -> Unit
) : RecyclerView.Adapter() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeroAdapter.HeroHolder {
return HeroHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.item_hero,
parent,
false
)
)
}
override fun getItemCount(): Int = heroes.size
override fun onBindViewHolder(holder: HeroAdapter.HeroHolder, position: Int) {
holder.binHero(heroes[position])
}
inner class HeroHolder(view: View) : RecyclerView.ViewHolder(view) {
fun binHero(hero: Hero) {
itemView.apply {
txtHeroName.text = hero.name
Picasso.get().load(hero.image).into(imgHeroes)
setOnClickListener {
adapterOnclick(hero)
}
}
}
}
}
this is my emulator
https://i.stack.imgur.com/0ePUC.png
I wrote this code using recyclerview and I got the image that I got from the url, why my image didn't appear, I wrote this code using the kotlin programming language
please help me

Gravity:End is not taking effect Programmatically

I am giving gravity:end in xml and it shows at the right side in Android Studio. (go end)
but programmatically doesn't work.
layout_gravity:end in chat_image worked just in Android Studio preview but it's not working programmatically.
changed item_parent to RelativeLayout but not work and same with LinearLayout
All possible cases I did when I saw right preview in xml with attributes gravity or layout_gravity if possible.
I think the problem related to Glide
-My code-
msg_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/item_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!--this item-->
<ImageView
android:id="#+id/chat_image"
android:layout_width="200dp"
android:layout_height="wrap_content"
/>
<LinearLayout
android:id="#+id/msg_linear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="#+id/user_id"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:textAppearance="#android:style/TextAppearance.Material.Large" />
<TextView
android:id="#+id/msg_area"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:textAppearance="#android:style/TextAppearance.Material.Large" />
</LinearLayout>
</LinearLayout>
TalkAdapter.kt
class TalkAdapter(val list: List<ChatDto>, val glide: RequestManager) :
RecyclerView.Adapter<TalkAdapter.ViewHolder>() {
private var mList = list as ArrayList<ChatDto>
private val myId = list[0].id
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TalkAdapter.ViewHolder =
ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.msg_item, parent, false))
override fun getItemCount(): Int = mList.size
override fun onBindViewHolder(holder: TalkAdapter.ViewHolder, position: Int) {
holder.itemView.apply {
if (mList[position].id == myId) {
msg_area.apply {
if (position != 0)
text = mList[position].msg
}
user_id.text = ""
//my intend
item_parent.gravity = Gravity.END
} else {
msg_area.apply {
text = mList[position].msg
//and this
gravity = Gravity.START
}
user_id.text = mList[position].id
item_parent.gravity = Gravity.START
}
chat_image.apply {
if (mList[position].uri != null) {
visibility = View.VISIBLE
glide.load(mList[position].uri)
.into(this)
} else {
visibility = View.GONE
}
}
}
}
fun addItem(item: ChatDto) {
mList.add(item)
Log.e("mList-size", mList.size.toString())
notifyItemInserted(mList.size - 1)
}
}
Problem:
Android Studio preview:

CardView not clickable

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
}

Categories

Resources