选择动态壁纸的背景

时间:2010-09-09 18:11:56

标签: android live-wallpaper

我正在编写一个可在背景上创建效果的动态壁纸。我希望用户能够从任何系统壁纸和相机照片中选择背景。我想要的是用户能够按下“设置”菜单中的按钮,显示选项列表就像在主屏幕上设置壁纸一样,减去动态壁纸选项。一旦用户导航选择并选择实际图像,我就会将其加载到我的画布上。

我该怎么做?

我无法在任何地方找到获取壁纸列表的API。

我已经能够使用Intent提供壁纸提供商列表。然后,我获得了一个使用Intents的动态壁纸提供商列表,并从我的第一个列表中删除它们。给我一个不活动的壁纸提供商列表。

现在怎样?还有其他方法可以解决这个问题吗?

请帮忙。

2 个答案:

答案 0 :(得分:25)

我通过将一个首选项放入Settings xml来实现这一点(我的是flash_setting.xml);

<Preference
    android:key="image_custom"
    android:title="Choose Background"
    android:summary="Select a Custom Image"
     />

我创建了一个自定义类来获取OnPreferenceClick侦听器并监视用户单击首选项(这是调用mySettings.java)(请注意,getRealPathFromURI例程不是我的,并且在此处的其他位置找到);


您的课程应首先扩展PreferenceActivity并实施Sharedpreference更改侦听器

public class flashSettings extends PreferenceActivityimplements SharedPreferences.OnSharedPreferenceChangeListener {    

链接到首选项名称并注册侦听器

@Override
protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    getPreferenceManager().setSharedPreferencesName(
            fingerflashpro.SHARED_PREFS_NAME);
    addPreferencesFromResource(R.xml.flash_settings);      getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(
            this);

接下来,我们将设置on首选项侦听器以侦听'image_custom'。单击它时,我们将启动一个新的意图来显示照片选择器。我们从StartActivityForResult开始,这样我们就可以从intent中获取图像的URI。

getPreferenceManager().findPreference("image_custom").setOnPreferenceClickListener(new OnPreferenceClickListener()
{
    @Override
    public boolean onPreferenceClick(Preference preference)
    {
        Display display = getWindowManager().getDefaultDisplay(); 
        int width = display.getWidth();
        int height = display.getHeight();
        Toast.makeText(getBaseContext(), "Select Image - " + (width) + " x " + height , Toast.LENGTH_LONG).show(); 
        Intent photoPickerIntent = new Intent(Intent.ACTION_PICK); 
        photoPickerIntent.setType("image/*");
        startActivityForResult(photoPickerIntent, 1);
        return true;
    }
});}

接下来,我们等待活动返回结果,并将URI解析为实际路径。

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
super.onActivityResult(requestCode, resultCode, data); 
if (requestCode == 1) {
if (resultCode == Activity.RESULT_OK) { 
  Uri selectedImage = data.getData();   
  String RealPath;
  SharedPreferences customSharedPreference = getSharedPreferences(fingerflashpro.SHARED_PREFS_NAME, Context.MODE_PRIVATE); 
  SharedPreferences.Editor editor = customSharedPreference.edit ();
  RealPath = getRealPathFromURI (selectedImage);
  editor.putString("image_custom", RealPath); 
  editor.commit(); 
}}

在这个网站上找到了以下代码(PercyPercy在this thread上),我只是为了完整性而包含它。但它确实很有效。

public String getRealPathFromURI(Uri contentUri) {          
String [] proj={MediaColumns.DATA};  
Cursor cursor = managedQuery( contentUri,  
        proj, // Which columns to return  
        null,       // WHERE clause; which rows to return (all rows)  
        null,       // WHERE clause selection arguments (none)  
        null); // Order-by clause (ascending by name)  
int column_index = cursor.getColumnIndexOrThrow(MediaColumns.DATA);  
cursor.moveToFirst();  
return cursor.getString(column_index);}

确保我们实施所需的覆盖;

@Override
protected void onResume() {
    super.onResume();
}

@Override
protected void onDestroy() {
    getPreferenceManager().getSharedPreferences().
       unregisterOnSharedPreferenceChangeListener(this);
    super.onDestroy();
}

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
        String key) {
}}

然后在您的主要壁纸服务活动中,您可以从共享的偏好设置中提取图像的路径。

@Override
    public void onSharedPreferenceChanged(SharedPreferences prefs,
            String key) {

        imageBg = prefs.getString("image_custom", "Bad Image");
            getBackground();}

这是加载图像的相当粗略的例程。我试图引入一些错误捕获,以防文件被删除,重命名或SD卡被挂载(因此你丢失了你的图像)。我还试图对设备方向进行一些粗略的检查。我相信你能做得更好。

还有一些Samplesize检查,因此您不会超过VM预算。这是此代码中最重要的部分,可以防止强制关闭,并且绝对应该包括在内。

我还会在更改手机方向时调用此例程,以便每次调整背景大小。

void getBackground() { 
        if (this.cvwidth == 0 || this.cvheight == 0 || this.visibleWidth == 0) {
               this.cvwidth = 480;
               this.cvheight = 854;
               this.visibleWidth = 480;}
        if(new File(imageBg).exists()) {
                int SampleSize = 1;
             do {
                 BitmapFactory.Options options = new BitmapFactory.Options();
                 options.inJustDecodeBounds = true;
                 bg = BitmapFactory.decodeFile(imageBg, options);
                SampleSize = (int) (Math.ceil(options.outWidth/(this.visibleWidth * 2))*2);
                options.inJustDecodeBounds = false;
                 try {options.inSampleSize = SampleSize;
                     bg = BitmapFactory.decodeFile(imageBg, options);}
                    catch (OutOfMemoryError e) {
                        SampleSize = SampleSize * 2;
                        }
                } while (bg == null);

           bg = Bitmap.createScaledBitmap(bg, this.cvwidth/2, this.cvheight, true);}
        else {bg = BitmapFactory.decodeResource(getResources(), R.drawable.bg);
            bg = Bitmap.createScaledBitmap(bg, this.cvwidth/2, this.cvheight, true);}
        LoadText = "";
    } 

我希望这会有所帮助。我花了一个绝对的年龄来提出所有这些,我知道还有一些方面我可以改进,但至少它应该让你去。

如果有人有关于使这段代码更好的建议,那么我全都听见了。

答案 1 :(得分:0)

不,这几乎是最好的方式。任何响应android.intent.action.SET_WALLPAPER的东西都是某种形式的壁纸提供者。问题是,给他们这个列表将使你的控制不在等式中。基本上让他们从其他提供商那里挑选一些东西会取消你的动态壁纸。您可以通过一些创造性的Manifest设置和/或一些“startActivityForResult”类型的调用来解决这个问题。

在他们选择了一些东西之后,虽然在WallpaperService.Engine中这是一件简单的事情:

@Override
public void onSurfaceChanged( SurfaceHolder holder, int format, int width, int height )
{
    super.onSurfaceChanged( holder, format, width, height );
    if( isVisible() )
    {
    mSurfaceHolder = holder;
    final Drawable drawable = WallpaperManager.getInstance( getBaseContext() ).getFastDrawable();
    mSurfaceHolder.setFormat( RenderThread.pixFormat );
    Canvas c = mSurfaceHolder.lockCanvas();
    if( c != null )
        {
            drawable.draw( c );
            mSurfaceHolder.unlockCanvasAndPost( c );
        }
    }
}