2013-04-09 36 views
4

我正在尝试制作一个简单的小部件,该部件可以在小部件中以文本方式和图形方式显示电池百分比。文本部分没有问题,但我很难让图形更新部件。当用作小部件的布局背景时,ClipDrawable不起作用

以图形方式,我有根据电池百分比剪辑的电池图像。我正在尝试使用ClipDrawable

battery_widget_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/widgetLayout" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:orientation="horizontal" 
    android:padding="@dimen/widget_padding" 
    android:background="@drawable/battery_clip_layer" > 

    <TextView 
     android:id="@+id/batteryPercentageWidgetTextView" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:text="@string/battery_percentage_widget_default" 
     android:gravity="center" /> 

</LinearLayout> 

battery_clip_layer.xml(即ClipDrawable)

<clip xmlns:android="http://schemas.android.com/apk/res/android" 
    android:clipOrientation="vertical" 
    android:gravity="bottom" 
    android:drawable="@drawable/battery_shape" /> 

BatteryService.java - 接收电池电压事件,并通过更新微件服务a RemoteViews

public class BatteryService extends Service { 

    private static final String LOG = BatteryService.class.getName(); 
    private final AtomicInteger batteryPercentage = new AtomicInteger(100); 

    private final BroadcastReceiver batteryUpdateReceiver = new BroadcastReceiver() { 

     @Override 
     public void onReceive(Context context, Intent intent) { 
      int level = intent.getIntExtra("level", 0); 
      batteryPercentage.set(level); 
      updateWidget(); 
     } 
    }; 


    @Override 
    public void onCreate() { 
     super.onCreate(); 
     registerReceiver(batteryUpdateReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 
     Log.i(LOG, "Created..."); 
    } 

    @Override 
    public void onDestroy() { 
     super.onDestroy(); 
     unregisterReceiver(batteryUpdateReceiver); 
     Log.i(LOG, "Destroyed..."); 
    } 

    @Override 
    public int onStartCommand(Intent intent, int flags, int startId) { 
     Log.i(LOG, "Started..."); 
     updateWidget(); 
     return super.onStartCommand(intent, flags, startId); 
    } 

    @Override 
    public IBinder onBind(Intent arg0) { 
     return null; 
    } 

    private void updateWidget() { 
     final int percentage = batteryPercentage.get(); 
     log.i(LOG, "Updated... " + percentage); 
     RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.battery_widget_layout); 
     remoteViews.setTextViewText(R.id.batteryPercentageWidgetTextView, percentage + "%"); 
     //ATTEMPT 1 - no cigar 
     remoteViews.setInt(R.drawable.battery_clip_layer, "setLevel", 5000); 
     AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); 
     appWidgetManager.updateAppWidget(new ComponentName(this, BatteryAppWidgetProvider.class), remoteViews); 
    } 

    private void updateWidgetAttempt2() { 
     final int percentage = batteryPercentage.get(); 
     Log.i(LOG, "Updated... " + percentage); 
     //ATTEMPT 2 - still no cigar 
     Drawable clipLayer = getApplicationContext().getResources().getDrawable(R.drawable.battery_clip_layer); 
     if (clipLayer instanceof ClipDrawable) { 
      ClipDrawable clipDrawable = (ClipDrawable) clipLayer; 
      int level = clipDrawable.getLevel(); 
      if (clipDrawable.setLevel(10000)) { 
       clipDrawable.invalidateSelf(); 
      } 
      Log.i(LOG, "Updated clip amount..." + level + " -> " + ((ClipDrawable) clipLayer).getLevel()); 
     } 
     RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.battery_widget_layout); 
     remoteViews.setTextViewText(R.id.batteryPercentageWidgetTextView, percentage + "%"); 
     AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); 
     appWidgetManager.updateAppWidget(new ComponentName(this, BatteryAppWidgetProvider.class), remoteViews); 
    } 

} 

BatteryService请看看两个不同的尝试来更新小部件(updateWidget()updateWidgetAttempt2())。这两种尝试都没有成功。

我觉得我正在做一些根本性的错误。我非常感谢任何帮助/建议! :)

+0

你的两次尝试是不正确的。在第一次尝试中,您错误地使用了'setInt()'方法,因为该方法期望第一个'int'成为窗口小部件布局中的'View'的标识(而不是像您尝试的可绘制引用)对任何视图都使用setLevel()方法,该方法存在于drawable类中。你的第二种方法也是不正确的,因为你所做的只是加载一个drawable,将其设置为level,这就是所有,与widget的LinearLayout没有关系。 – Luksprog 2013-04-13 09:58:28

+0

要使用'ClipDrawble',你需要能够在它已经被设置为背景时获得对它的引用,并且改变它的等级或者设置它的等级,然后将其设置为背景。我怀疑你可以使用目标视图在widget中执行上述任何操作。 – Luksprog 2013-04-13 10:00:03

+0

@Luksprog谢谢,能否请您在回答中发布上述信息,我会奖励您的赏金。 – Muel 2013-04-16 08:11:53

回答

4

您是正确的,因为您需要设置Drawable实例的级别,但不幸的是,您无法获取Drawable,因为它位于远程视图中。

但是,ImageView确实有一个名为setImageLevel的方法,您可以远程调用该方法。我的建议是将Drawable放在ImageView中,而不是作为容器的背景,然后使用setInt(R.id.image_view, "setImageLevel", level)

这里的布局应该是什么样子:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/widgetLayout" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:padding="@dimen/widget_padding" > 

    <ImageView 
     android:id="@+id/battery" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:src="@drawable/battery_clip_layer" /> 

    <TextView 
     android:id="@+id/batteryPercentageWidgetTextView" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:text="@string/battery_percentage_widget_default" 
     android:gravity="center" /> 

</FrameLayout> 

而且updateWidget()方法:您

private void updateWidget() { 
    final int percentage = batteryPercentage.get(); 
    log.i(LOG, "Updated... " + percentage); 

    RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.battery_widget_layout); 
    remoteViews.setTextViewText(R.id.batteryPercentageWidgetTextView, percentage + "%"); 

    remoteViews.setInt(R.id.battery, "setImageLevel", percentage * 100); 

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this); 
    appWidgetManager.updateAppWidget(new ComponentName(this, BatteryAppWidgetProvider.class), remoteViews); 
} 
+0

是的,这将是我的下一次尝试。不幸的是,根据奖金条件,我不能奖赏你的赏金,“我不会奖励其他解决方案的赏金,例如将LinearView添加到LinearLayout。”但我可以接受你的答案。一旦确认,我会这样做。 – Muel 2013-04-16 08:11:03

+0

感谢您的回答。这很好用,而且我可以在RemoteViews中的'FrameLayout'内控制多个ImageViews。 – Muel 2013-04-20 02:00:08

0

两个尝试使用在小部件ClipDrawable是不正确有关。在第一次尝试中,您错误地使用了setInt()方法,因为该方法预计参数的第一个int将是窗口小部件的布局中的的id(并且不像您尝试的那样是可绘制引用),所以也没有setLevel()方法View子类来自Android SDK,该方法存在于Drawable类中。你的第二种方法也是不正确的,因为你所做的只是加载一个Drawable,设置它的级别,这就是新创建的Drawable与小部件的LinearLayout根没有关系。

要使ClipDrawable工作,您需要将其级别设置为所需的值,而绘图已经设置为LinearLayout的背景或者您可以将其设置为背景。不幸的是,当布局用在一个小部件中时,我看不出如何做到这一点。

您需要使用解决方法(Jschools提供了一个)。