Edit 4/5: My getViewAt
function is now this, and still no effect occurs
override fun getViewAt(position: Int): RemoteViews {
val v = (context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
.inflate(R.layout.widget_item, null)
.findViewById<ProgressBar>(R.id.progressBar)
.apply {
this.progressBackgroundTintList = ColorStateList.valueOf(0x00ff00)
this.progressTintList = ColorStateList.valueOf(0xffff00)
this.max = 100
this.progress = 0
this.isIndeterminate = false
this.progressDrawable = context.resources.getDrawable(R.drawable.circle_progress_bar, null)
}
val layer = context.resources.getDrawable(R.drawable.circle_progress_bar, null) as LayerDrawable
layer.getDrawable(0).setColorFilter(0x03a9f4, android.graphics.PorterDuff.Mode.SRC_IN)
layer.getDrawable(1).setColorFilter(0x8bc34a, android.graphics.PorterDuff.Mode.SRC_IN)
View.inflate(context, R.layout.widget_item, null)
.findViewById<ProgressBar>(R.id.progressBar)
.progressDrawable = layer
val r = RemoteViews(context.packageName, R.layout.widget_item).apply {
val event = MiniModel.events[position]
// setProgressBar(
// R.id.progressBar,
// event.totalDuration.toInt(unit = DurationUnit.SECONDS),
// event.timeRemaining.toInt(unit = DurationUnit.SECONDS),
// false
// )
reapply(context, v)
setTextViewText(R.id.item_text, event.title)
setTextViewText(R.id.details_text, if (event.isOver) "Event Complete" else "in " + event.timeRemaining.asPrettyString)
}
View.inflate(context, r.layoutId, null).findViewById<ProgressBar>(R.id.progressBar)
.apply {
this.progressBackgroundTintList = ColorStateList.valueOf(0x00ff00)
this.progressTintList = ColorStateList.valueOf(0xffff00)
this.max = 100
this.progress = 0
this.isIndeterminate = false
this.progressDrawable = context.resources.getDrawable(R.drawable.circle_progress_bar, null)
}
return r
}
I'm making an Android app widget which is a ListView with n rows. In each row, I have a custom circular progress indicator, which has two colors; one for the background and one for the foreground. The progress indicator's colors are different for each row, but are based on the same Drawable resource.
My question is, when setting up / updating my widget, how can I change the progress indicators colors in each row? Another challenge is that I don't have access to findViewById
since I construct my widget using a RemoteViewsFactory
.
@drawable/circle_progress_bar.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape
android:innerRadiusRatio="1000"
android:shape="ring"
android:thicknessRatio="10"
android:useLevel="false">
<solid android:color="#0000ff" /> <!-- I want this to be set programatically per widget row -->
</shape>
</item>
<item android:id="@android:id/progress">
<rotate
android:fromDegrees="270"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="270">
<shape
android:innerRadiusRatio="1000"
android:shape="ring"
android:thicknessRatio="10"
android:useLevel="true">
<solid android:color="#ff0000" /> <!-- this too -->
</shape>
</rotate>
</item>
</layer-list>
@layout/widget_item.xml
<?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="80dp"
android:background="@drawable/shape"
android:gravity="center_vertical">
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:scaleX="2"
android:scaleY="2"
android:layout_width="100dp"
android:layout_height="60dp"
android:layout_weight="0"
android:indeterminate="false"
android:max="100"
android:progress="25"
android:progressDrawable="@drawable/circle_progress_bar" />
</LinearLayout>
EventWidgetService.kt
class EventWidgetService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent): RemoteViewsFactory =
EventRemoteViewsFactory(this.applicationContext, intent)
}
class EventRemoteViewsFactory(private val context: Context, intent: Intent) : RemoteViewsService.RemoteViewsFactory {
private val prefsName = "FlutterSharedPreferences"
override fun onCreate() {
MiniModel.initialize(context.getSharedPreferences(prefsName, Context.MODE_PRIVATE))
}
override fun getLoadingView(): RemoteViews = RemoteViews(context.packageName, R.id.emptyView)
override fun getItemId(position: Int): Long = position.toLong()
override fun onDataSetChanged() {
}
override fun hasStableIds(): Boolean = true
@ExperimentalTime
override fun getViewAt(position: Int): RemoteViews {
return RemoteViews(context.packageName, R.layout.widget_item).apply {
val event = MiniModel.events[position]
setProgressBar(
R.id.progressBar,
(event.end.epochSecond - event.start.epochSecond).toInt(),
event.secondsRemaining.toInt(unit = TimeUnit.SECONDS),
false
)
setTextViewText(R.id.item_text, event.title)
setTextViewText(R.id.details_text, if (event.isOver) "Event Complete" else "in " + event.secondsRemaining.asPrettyString)
}
}
override fun getCount(): Int = MiniModel.events.count()
override fun getViewTypeCount(): Int = 1
override fun onDestroy() {
}
}
Edits 1 / 2 Summary Reflection doesn't work
Edit 3: In my getViewAt(Int): RemoteViews
function, I also tried adding
View.inflate(context, R.layout.widget_item, null).findViewById<ProgressBar(R.id.progressBar).apply {
progressBackgroundTintList = ColorStateList.valueOf(0x00ff00)
progressTintList = ColorStateList.valueOf(0xffff00)
}
however this does not have any effect.