第四章 A Frame with a View

 

          A Frame with a View

对于 MFC 程序员来说通常是把框架窗口的客户区作为一个分离的视图类子窗口来管理 . 主框架窗口负责 装饰 工作 , 如菜单条和工具条的安置 . 而视图类则仅仅负责呈现应用程序最重要的信息 . 这种抽象对处理 MDI 和分割窗口非常便利 , 稍后我们再详细讨论它们 .

视图类可以是具有窗口句柄 HWND 的任何东西 ( MFC 中视图类必须是 CWnd 及其子类 ), 在主框架窗口 WM_CREATE 消息映射函数中把其成员变量 m_hWndClient 设置为 HWND 即可 . 例如可以把咱们的 SDI 程序位图绘制功能移植到视图类中完成 , 你可以如下定义一个视图类 :

class CBitmapView : public CWindowImpl<CBitmapView> {

public:

    CBitmapView();

    ~CBitmapView();

    BEGIN_MSG_MAP(CBitmapView)

        MESSAGE_HANDLER(WM_PAINT, OnPaint)

    END_MSG_MAP()

    LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL&);

private:

    HBITMAP          m_hBmp;

};

 

如下使用此视图类:

LRESULT OnCreate(UINT, WPARAM, LPARAM, BOOL&) {

    // Create the View (m_view is of type CBitmapView)

    m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL,

                                 WS_CHILD | WS_VISIBLE,

                                  WS_EX_CLIENTEDGE);

    return 0;

}

 

现在 , 当框架窗口大小发生变化时 , 视图类能自动调整其大小并与菜单栏 , 工具条 , 命令条和状态条紧密衔接充满整个框架窗口区域 .

ATL WTL 的大部分窗口类都能作为视图类来工作 . 你可以使用所有窗口控件类和通用控件封装类作为视图类 . 例如 , m_view CBitmapView 类改为 CEdit 控件类 ( 定义在 atlctrls.h), 你就有了一个自己的文字编辑器 ( Figure 6)

 

                Figure 6: Simple Text Editor

 

 

 

 

如果你想继承自一个 ATL 窗口封装类并将其作为视图类 , 你可以用两种不同的继承方法来实现 : C++ 方法继承和窗口化方法 ---- 超类化 ( super-classing ), 这样就可以添加额外功能和消息处理 . 例如 , 继承自 CAxWindow , 你可以处理 HTML 网页 .

 

// Inherit the C++ way to inherit CAxWindow functionality

class CHtmlView : public CWindowImpl<CHtmlView, CAxWindow > {

public:

    // Inherit the Windows way to pre-process Windows messages

    DECLARE_WND_SUPERCLASS(NULL, CAxWindow::GetWndClassName())

 

    BEGIN_MSG_MAP(CHtmlView)

    …

    END_MSG_MAP()

 

    CHtmlView() {

        // Init control hosting (defined in atlhost.h)

        AtlAxWinInit();

    }

};

 

我们可以用此视图类来处理网页浏览了 (Figure 7 显示了效果 )

 

LRESULT CMainFrame::OnCreate(UINT, WPARAM, LPARAM, BOOL&)

{

    // Create the View (m_view is of type CHtmlView)

    m_hWndClient = m_view.Create(m_hWnd, rcDefault,

                                 "http://www.microsoft.com",

                                 WS_CHILD | WS_VISIBLE,

                                 WS_EX_CLIENTEDGE);

    return 0;

}

 

                Figure 7: Using the New View to Host a Web Page

 

 

 

 

Maintaining the MRU

To be continued···

<think>我们将使用Glide和Android的RenderScript(或替代方案,因为RenderScript已弃用)来实现对View的模糊处理。 由于RenderScript在API 31后被弃用,我们可以使用其他库如GlideTransformations(第三方)或使用Android内置的RenderScriptCompat(仍可用但不再推荐)或使用其他模糊算法。 这里我们使用GlideTransformations库,因为它简单且与Glide集成良好。 步骤: 1. 添加依赖 2. 使用Glide加载图片并应用模糊变换 注意:如果要对任意View(不仅仅是ImageView)进行模糊处理,我们可以先获取View的Bitmap,然后使用Glide加载这个Bitmap并应用模糊变换,再将结果设置到目标View上。但是,Glide通常用于加载网络或资源图片到ImageView。对于任意View的模糊,我们可以考虑以下方法: a. 将View绘制到一个Bitmap上 b. 使用Glide加载这个Bitmap并应用模糊变换 c. 将模糊后的Bitmap设置到一个ImageView(覆盖在原始View上)或者直接设置到View的背景等 但是,Glide本身并不直接支持对任意View进行模糊,而是对图片资源进行变换。因此,我们需要先将View转换为Bitmap,然后通过Glide来处理。 然而,直接使用Glide来处理View转换的Bitmap可能不是最佳实践,因为Glide主要用于图片加载。另一种做法是使用其他模糊方法(如使用Android内置的RenderScriptCompat或使用快速模糊算法)直接处理Bitmap。 这里,我们展示两种方式: 方式1:使用GlideTransformations库对图片资源进行模糊(例如,加载一个Drawable资源或网络图片到ImageView,并模糊) 方式2:对任意View进行模糊(通过将View绘制成Bitmap,然后使用GlideTransformations进行模糊处理,并将结果设置到一个覆盖的ImageView上) 由于问题要求使用Glide,我们主要展示方式1,并补充方式2的关键步骤。 方式1:使用Glide加载图片并应用模糊变换(针对ImageView) 添加依赖(在build.gradle模块中): ```groovy dependencies { implementation 'com.github.bumptech.glide:glide:4.12.0' implementation 'jp.wasabeef:glide-transformations:4.3.0' // 如果你使用kotlin,可能需要kapt注解处理器,这里我们使用java } ``` 示例代码(加载图片到ImageView并模糊): ```java import android.os.Bundle; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; import com.bumptech.glide.Glide; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.request.RequestOptions; import jp.wasabeef.glide.transformations.BlurTransformation; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ImageView imageView = findViewById(R.id.imageView); // 使用Glide加载图片并应用模糊变换 Glide.with(this) .load(R.drawable.your_image) // 可以是资源id、url、文件等 .apply(RequestOptions.bitmapTransform( new BlurTransformation(25, 3) // 半径25,采样倍数3(值越大越模糊,但性能开销越大) )) .diskCacheStrategy(DiskCacheStrategy.ALL) // 缓存策略 .into(imageView); } } ``` 方式2:对任意View进行模糊处理(例如整个布局) 思路: 1. 获取目标View的Bitmap 2. 使用Glide加载这个Bitmap并应用模糊变换 3. 将模糊后的图片设置到一个覆盖在整个View上的ImageView 注意:获取View的Bitmap需要在View已经布局完成之后,因此需要在View的onWindowFocusChanged或使用ViewTreeObserver。 示例代码(对任意View进行模糊): ```java import android.graphics.Bitmap; import android.graphics.Canvas; import android.os.Bundle; import android.view.View; import android.view.ViewTreeObserver; import android.widget.FrameLayout; import android.widget.ImageView; import androidx.appcompat.app.AppCompatActivity; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.SimpleTarget; import com.bumptech.glide.request.transition.Transition; import jp.wasabeef.glide.transformations.BlurTransformation; public class BlurActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_blur); final View rootView = findViewById(R.id.root_view); // 要模糊的根布局 final FrameLayout frameLayout = findViewById(R.id.frame_layout); // 用于放置模糊图片的容器 // 等待布局完成 rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); // 1. 获取View的Bitmap Bitmap bitmap = getViewBitmap(rootView); // 2. 使用Glide进行模糊处理 Glide.with(BlurActivity.this) .asBitmap() .load(bitmap) .apply(RequestOptions.bitmapTransform(new BlurTransformation(25, 3))) .into(new SimpleTarget<Bitmap>() { @Override public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) { // 3. 将模糊后的Bitmap设置到覆盖的ImageView上 ImageView blurredImageView = new ImageView(BlurActivity.this); blurredImageView.setImageBitmap(resource); blurredImageView.setScaleType(ImageView.ScaleType.CENTER_CROP); // 添加到覆盖层 frameLayout.addView(blurredImageView); } }); } }); } // 将View转换成Bitmap private Bitmap getViewBitmap(View view) { Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap; } } ``` 注意:这种方式会消耗较多内存,特别是对于大视图进行模糊时。建议在实际使用中考虑性能优化,例如降低采样率、使用缩略图等。 解释: 1. 方式1:直接使用Glide加载图片资源并应用BlurTransformation,适用于ImageView显示图片的情况。 2. 方式2:适用于对任意View(如整个布局)进行模糊。我们首先将View绘制成Bitmap,然后使用Glide加载这个Bitmap并应用模糊变换,最后将模糊后的图片添加到一个覆盖的ImageView上。 关于BlurTransformation的参数: - 模糊半径(radius):通常1-25,值越大越模糊 - 采样倍数(sampling):用于缩小原图再进行模糊处理,可以提升性能(例如采样倍数为2,则宽高各缩小2倍,模糊后再放大,性能提升明显) 注意事项: - 模糊处理是耗时的,尽量避免在主线程进行(Glide默认在后台线程处理变换) - 对于大图或高采样倍数,可能会造成内存问题,需适当调整参数 - 由于方式2需要获取整个View的Bitmap,需要确保View已经完成布局(宽高不为0) 替代方案:如果不想使用第三方库,可以考虑使用Android内置的RenderScript(尽管已弃用),或者使用快速模糊算法(如StackBlur)自行实现变换。 §§相关问题§§: 1. 如何在不使用第三方库的情况下实现图片模糊效果? 2. Glide的图片变换如何自定义? 3. 如何优化大图模糊时的内存和性能? 4. 除了模糊处理,Glide还支持哪些常见的图片变换? </think># Glide 对 View 进行模糊处理的完整指南 在 Android 开发中,使用 Glide 对 View 进行模糊处理是一种常见的视觉效果实现方式。下面我将详细介绍如何使用 Glide 实现 View 的模糊效果,并提供完整的代码实现。 ## 解决方案概述 要实现 View 的模糊处理,我们需要: 1. 将 View 渲染为 Bitmap 2. 使用 Glide 的变换功能对 Bitmap 进行模糊处理 3. 将处理后的 Bitmap 应用到目标 View 以下是完整的实现代码: ```java import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.bumptech.glide.Glide; import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.engine.DiskCacheStrategy; import com.bumptech.glide.load.engine.GlideException; import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; import com.bumptech.glide.request.RequestListener; import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.target.Target; import java.security.MessageDigest; import jp.wasabeef.glide.transformations.BlurTransformation; public class ViewBlurUtil { /** * 对指定View进行模糊处理 * @param context 上下文 * @param targetView 需要模糊的目标View * @param blurView 用于显示模糊效果的ImageView * @param blurRadius 模糊半径 (1-25) * @param sampling 采样率 (1-8,值越大性能越好但质量越低) */ public static void applyBlurToView(Context context, View targetView, ImageView blurView, int blurRadius, int sampling) { // 获取目标View的Bitmap Bitmap bitmap = getBitmapFromView(targetView); if (bitmap != null) { // 使用Glide应用模糊变换 Glide.with(context) .asBitmap() .load(bitmap) .apply(new RequestOptions() .transform(new BlurTransformation(blurRadius, sampling)) .diskCacheStrategy(DiskCacheStrategy.NONE) // 禁用缓存 .skipMemoryCache(true)) // 跳过内存缓存 .listener(new RequestListener<Bitmap>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) { // 设置模糊后的图像 blurView.setImageBitmap(resource); return true; } }) .into(blurView); } } /** * 将View转换为Bitmap */ private static Bitmap getBitmapFromView(View view) { if (view.getWidth() <= 0 || view.getHeight() <= 0) { return null; } Bitmap bitmap = Bitmap.createBitmap( view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888 ); Canvas canvas = new Canvas(bitmap); view.draw(canvas); return bitmap; } } ``` ## 使用方法 在 Activity 或 Fragment 中使用: ```java // 在布局中使用FrameLayout包含目标View和模糊View <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 目标View --> <LinearLayout android:id="@+id/target_view" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 这里放置你的内容 --> </LinearLayout> <!-- 模糊效果View --> <ImageView android:id="@+id/blur_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop"/> </FrameLayout> // 在Java代码中调用 View targetView = findViewById(R.id.target_view); ImageView blurView = findViewById(R.id.blur_view); // 应用模糊效果(模糊半径15,采样率4) ViewBlurUtil.applyBlurToView(this, targetView, blurView, 15, 4); ``` ## 代码解释 ### 1. 获取 View 的 Bitmap - `getBitmapFromView()` 方法将目标 View 绘制到 Bitmap 上 - 使用 `Canvas` 来渲染 View 的内容到 Bitmap ### 2. Glide 模糊处理 - 使用 `BlurTransformation` 实现模糊效果 - 参数说明: - `blurRadius`:模糊半径 (1-25),值越大越模糊 - `sampling`:采样率 (1-8),值越高性能越好但质量越低 - 禁用缓存 (`diskCacheStrategy(DiskCacheStrategy.NONE)` 和 `skipMemoryCache(true)`) 确保每次都能获取最新内容 ### 3. 显示结果 - 使用 `RequestListener` 在模糊处理完成后更新 ImageView - 模糊后的 Bitmap 设置为 ImageView 的内容 ## 性能优化技巧 1. **降低采样率**: - 对于大尺寸 View,使用采样率 4-8 可显著提升性能 - 对于小尺寸 View,使用采样率 1-2 保持高质量 2. **模糊半径选择**: - 15-25 用于强模糊效果(如背景模糊) - 5-15 用于适度模糊(如对话框背景) - 1-5 用于轻微模糊效果 3. **缓存优化**: - 如果内容不常变,可启用缓存 - 动态内容需禁用缓存 4. **替代方案**: - 对于静态内容,可预先生成模糊图像 - 考虑使用 RenderScript(API 17+),但需注意兼容性 ## 依赖配置 在 `build.gradle` 中添加以下依赖: ```gradle dependencies { implementation 'com.github.bumptech.glide:glide:4.13.2' implementation 'jp.wasabeef:glide-transformations:4.3.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.13.2' } ``` ## 注意事项 1. **时机问题**: - 确保在 View 完成布局后调用(如 `onWindowFocusChanged()` 中) - 可在 `ViewTreeObserver.OnGlobalLayoutListener` 中确保 View 已布局 2. **内存管理**: - 大尺寸 Bitmap 可能导致 OOM - 考虑缩小 Bitmap 尺寸或增加采样率 3. **动态内容**: - 对于频繁更新的 View,考虑使用其他模糊方案 - 可限制模糊更新的频率(如使用节流)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值