Android: Appwidget with Custom View Not Working

Android: AppWidget with custom view not working

I pretty much left my custom view intact, and implemented an ImageView for my widget, then rendered the view using the getDrawingCache()

MyView myView = new MyView(context);
myView.measure(150,150);
myView.layout(0,0,150,150);
myView.setDrawingCacheEnabled(true);
Bitmap bitmap=myView.getDrawingCache();
remoteViews.setImageViewBitmap(R.id.dial, bitmap);

Why there is not support for custom views in widgets?

Widgets are such a big part of users interaction with the app

Few apps implement app widgets.

Is there a specific reason why this was made

Both the host of the app widget (e.g., home screen/launcher) and the publisher of the app widget need to agree on what UI elements can be used and how they can be configured.

For example, you seem to want to use a RecyclerView. That's fine, however, your app does not render the app widget. The host is the one that needs to render the UI of the app widget. So, if you were to use a RecyclerView, your app widget would fail on all hosts that lack RecyclerView support for app widgets. This includes:

  • All hosts that have not been updated since before RecyclerView was introduced (e.g., home screens on older devices)

  • All hosts that did not bother to bundle in RecyclerView in their apps

  • All hosts that did not bother to bundle in whatever the code would be that would cause app widget rendering to support RecyclerView

This coordination gets very complex with hundreds or thousands of hosts and tens or hundreds of thousands of app widgets.

Plus, where does it stop? You think that using RecyclerView is reasonable, and the next person will think that using Facebook's Litho is reasonable, and the person after that will think that using some obscure custom View found on the Android Arsenal is reasonable.

The simple approach for ensuring this agreement is to use a common definition in the framework classes, like RemoteViews, so there is a guaranteed-consistent definition between host and app widget provider. However, RemoteViews is difficult to change in a backwards-compatible fashion, which is why Google has only done it once to date (API Level 11, with the introduction of AdapterView-based options, such as ListView). And framework classes know nothing about libraries, such as those providing RecyclerView or Litho.

My custom view is not being shown how should I fixed it?

You're overriding onLayout but there's no code in it. So when the view needs to lay itself out... it doesn't! Remove the onLayout function and it should work.


Also, don't call inflate in that init function. You already inflated the layout and added it to your custom view here:

private val binding = ItemStickerBinding.inflate(LayoutInflater.from(context),this,true)

If you inflate again, you create a new layout and replace the old one. binding was created from the old layout, and all its references point to the old views.

You also don't want this, it's a duplicate layout:

<include layout="@layout/item_sticker"/>

Just as an example of how I'd write this class with view binding - maybe it helps! It should be easier to work with anyway:

// subclass FrameLayout instead - you're inflating a layout and putting it -inside-
// your custom view, so a FrameLayout (which is meant to hold a single view) is better
// and safer than a ConstraintLayout (which you're not providing constraints for -
// it could break at some point, or act weird)

// I've removed the View.OnClickListener interface because I'm setting the listeners
// another way
class StickerView @JvmOverloads constructor(
context: Context,
attributeSet: AttributeSet?=null,
defStyle:Int = 0
) : FrameLayout(context,attributeSet,defStyle) {

// this inflates your layout and adds it to the view - job done!
private val binding =
ItemStickerBinding.inflate(LayoutInflater.from(context),this,true)

// If you need to refer to a view you've bound, you usually do it through
// the binding object - so "binding.appCompatButton0" etc, and there are ways
// to avoid saying "binding" all the time (see the init block below).
// But if you really want aliases, you could do it this way:
val btn0: ImageButton get() = binding.appCompatButton

init {
// this lets you avoid saying binding.this, binding.that - it can look neater
with(binding) {
// set a single click listener on multiple views
listOf(
appCompatButton, appCompatButton1, appCompatButton2,
appCompatButton3, appCompatButton4, appCompatButton5, appCompatButton6
).forEach { button ->
// call our onClick function with the clicked view
button.setOnClickListener { view -> onClick(view)}
// or setOnClickListener(::onClick)
}

// or you could set each button's action here, like this
appCompatButton1.setOnClickListener { doThing() }
appCompatButton2.setOnClickListener { doSomethingElse() }
}
}

// handle all your button clicks in a function if you want -
// v doesn't need to be nullable
private fun onClick(v: View) {
// because you're using view binding, you have references to all the views -
// so you don't need to use IDs at all
when (v) {
binding.appCompatButton -> { doThing() }
}

}

Personally, if you want the buttons to be named btn0 etc, I'd rename their IDs from appCompatButton to btn0 - that way you can refer to them as binding.btn0, if that's how you prefer to think about it! Give them the names you want to use.

Hope that helps!

Android widgets not showing on screen

check out logcat and look for some Exception. App widgets are crashing "silently" without any dialog, just doesn't appear. But you should be able to find cause of problem in logs

in your code I see one wrong line:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
...
android:configure="com.app24.test.mAppWidgetProvider"
...

android:configure should point on some Activity, which will be started when your widget will be added to home screen. your line points wrongly on your custom AppWidgetProvider, which isn't an Acticity - system probably tries to start this class as Activity or maybe checks instanceof and as this class isn't Activity then crash occurs. try to remove this line for start (or point on proper class)

Can't bind a custom view

This is the alternate method to define custom view in layout xml.

 <com.deadballapp.deadball.ui.pitch.PitchLiveView
android:id="@+id/view_pitch_live"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/nav_header_vertical_spacing"
android:layout_marginBottom="@dimen/btm_sheet_peek_height" />

You can bind this as other views, either by using View Binding or findViewById



Related Topics



Leave a reply



Submit