前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >android实现截图并动画消失效果的思路详解

android实现截图并动画消失效果的思路详解

作者头像
砸漏
发布2020-10-16 10:33:52
1.5K0
发布2020-10-16 10:33:52
举报
文章被收录于专栏:恩蓝脚本恩蓝脚本
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

整体思路

1、获取要截图的view 2、根据这个view创建Bitmap 3、保存图片,拿到图片路径 4、把图片路径传入自定义view(自定义view实现的功能:画圆角边框,动画缩小至消失) 主要用到的是ObjectAnimator属性动画的缩小和平移

核心代码

得到图片的路径

代码语言:javascript
复制
private String getFilePath() {
 Bitmap bitmap = createViewBitmap(picImg);
 if (bitmap != null) {
  try {
  // 首先保存图片
  String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "HIS";
  File appDir = new File(storePath);
  if (!appDir.exists()) {
   appDir.mkdir();
  }
  String fileName = System.currentTimeMillis() + ".jpg";
  File file = new File(appDir, fileName);

  BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
  bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
  bos.flush();
  bos.close();
  Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
  Uri uri = Uri.fromFile(file);
  intent.setData(uri);
  sendBroadcast(intent);
  return file.getAbsolutePath();
  } catch (Exception e) {
  return null;
  }
 } else {
  return null;
 }

 }
public Bitmap createViewBitmap(View v) {
 Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
 Canvas canvas = new Canvas(bitmap);
 v.draw(canvas);
 return bitmap;
 }

把图片路径传入自定义view

代码语言:javascript
复制
String filePath = getFilePath();
 mDisplayScreenshotSnv.setVisibility(View.GONE);
 mDisplayScreenshotSnv.setPath(filePath, picImg.getMeasuredWidth(), picImg.getMeasuredHeight(), true);
 mDisplayScreenshotSnv.setVisibility(View.VISIBLE);

截图实现圆角边框和动画消失

代码语言:javascript
复制
//实现截图动画(添加圆角边框)
  Glide.with(getContext())
   .load(new File(path))
   .transform(new CenterCrop(getContext()), new GlideRoundTransform(getContext(), radius))
   .crossFade()
   .listener(new RequestListener<File, GlideDrawable () {
    @Override
    public boolean onException(Exception e, File model, Target<GlideDrawable  target, boolean isFirstResource) {
    if (anim) {
     anim(thumb, true);
    }
    return false;
    }

    @Override
    public boolean onResourceReady(GlideDrawable resource, File model, Target<GlideDrawable  target, boolean isFromMemoryCache, boolean isFirstResource) {
    if (thumb.getDrawable() == null) {
     // 避免截图成功时出现短暂的全屏白色背景
     thumb.setImageDrawable(resource);
    }
    if (anim) {
     anim(thumb, true);
    }
    return false;
    }
   }).into(thumb);

  //启动延时关闭截图(显示5秒消失截图)
  startTick(true);

动画设置

代码语言:javascript
复制
/**
 * 动画设置
 * @param view
 * @param start
 */
 private void anim(final ImageView view, boolean start) {
 if (!start) {
  if (getChildCount()   0) {
  // 快速点击截图时,上一次添加的子视图尚未移除,需重置视图
  resetView();
  }
  setScaleX(1f);
  setScaleY(1f);
  setTranslationX(0f);
  setTranslationY(0f);
  clearAnimation();
  if (mScaleXAnim != null) {
  mScaleXAnim.cancel();
  mScaleXAnim = null;
  }
  if (mScaleYAnim != null) {
  mScaleYAnim.cancel();
  mScaleYAnim = null;
  }
  if (mTranslationXAnim != null) {
  mTranslationXAnim.cancel();
  mTranslationXAnim = null;
  }
  if (mTranslationYAnim != null) {
  mTranslationYAnim.cancel();
  mTranslationYAnim = null;
  }
  return;
 }

 view.post(new Runnable() {
  @Override
  public void run() {
  if (!view.isAttachedToWindow()) {
   // 子视图已被移除
   return;
  }
  setCardBackgroundColor(Color.WHITE);

  //等待cross fade动画
  float margins = DisplayUtil.dip2px(getContext(), 10);
  float scaleToX = (float) mFinalW / getMeasuredWidth();
  float scaleToY = (float) mFinalH / getMeasuredHeight();
  float translateToX = -(getMeasuredWidth() / 2f - (mFinalW / 2 + margins));
  float translateToY = getMeasuredHeight() / 2f - (mFinalH / 2f + margins);

  //以当前view为中心,x轴右为正,左为负;y轴下为正,上为负

  mScaleXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleX", 1.0f, scaleToX);
  mScaleYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleY", 1.0f, scaleToY);

  mTranslationXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationX", 1.0f, translateToX);
  mTranslationYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationY", 1.0f, translateToY);

  //设置速度
  mScaleXAnim.setDuration(500);
  mScaleYAnim.setDuration(500);
  mTranslationXAnim.setDuration(500);
  mTranslationYAnim.setDuration(500);

  //缩放
  mScaleXAnim.start();
  mScaleYAnim.start();
  //平移
  mTranslationXAnim.start();
  mTranslationYAnim.start();
  setEnabled(false);
  mScaleXAnim.addListener(new AnimatorListenerAdapter() {
   @Override
   public void onAnimationCancel(Animator animation) {
   super.onAnimationCancel(animation);
   setEnabled(true);
   }

   @Override
   public void onAnimationEnd(Animator animation) {
   super.onAnimationEnd(animation);
   setEnabled(true);
   setClickable(true);
   }

   @Override
   public void onAnimationStart(Animator animation) {
   super.onAnimationStart(animation);
   }
  });

  }
 });
 }

完整代码

ScreenshotNotifyView.java

代码语言:javascript
复制
package com.lyw.myproject.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.lyw.myproject.screenshot.GlideRoundTransform;
import com.lyw.myproject.utils.DisplayUtil;
import java.io.File;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.cardview.widget.CardView;
public class ScreenshotNotifyView extends CardView {
private int mFinalW;
private int mFinalH;
private Handler mHandler;
private ObjectAnimator mScaleXAnim = null;
private ObjectAnimator mScaleYAnim = null;
private ObjectAnimator mTranslationXAnim = null;
private ObjectAnimator mTranslationYAnim = null;
public ScreenshotNotifyView(@NonNull Context context) {
super(context);
init(context);
}
public ScreenshotNotifyView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ScreenshotNotifyView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@Override
public void setVisibility(int visibility) {
super.setVisibility(visibility);
if (visibility == GONE) {
resetView();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
anim(null, false);
startTick(false);
}
private void init(Context context) {
mHandler = new Handler(Looper.getMainLooper());
setCardElevation(0);
}
public void setPath(final String path, int w, int h, final boolean anim) {
setClickable(false);
anim(null, false);
final ImageView thumb = new ImageView(getContext());
FrameLayout.LayoutParams thumbParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
int padding = (int) DisplayUtil.dip2px(getContext(), 2);
int margins = (int) DisplayUtil.dip2px(getContext(), 8);
//设置截图之后的宽度,高度按照比例设置
mFinalW = (int) DisplayUtil.dip2px(getContext(), 90);
mFinalH = (int) ((float) mFinalW * h) / w;
if (!anim) {
//设置边框
params.setMargins(margins, margins, margins, margins);
margins = (int) DisplayUtil.dip2px(getContext(), 2);
params.width = mFinalW + margins * 2;
params.height = mFinalH + margins * 2;
params.gravity = Gravity.START | Gravity.BOTTOM;
thumbParams.width = mFinalW;
thumbParams.height = mFinalH;
thumbParams.gravity = Gravity.CENTER;
setLayoutParams(params);
requestLayout();
} else {
//设置边框
thumbParams.setMargins(margins, margins, margins, margins);
params.setMargins(0, 0, 0, 0);
params.width = FrameLayout.LayoutParams.MATCH_PARENT;
params.height = FrameLayout.LayoutParams.MATCH_PARENT;
setLayoutParams(params);
requestLayout();
}
thumb.setScaleType(ImageView.ScaleType.FIT_XY);
thumb.setLayoutParams(thumbParams);
addView(thumb);
post(new Runnable() {
@Override
public void run() {
float scale = (float) mFinalW / getMeasuredWidth();
int radius = 5;
if (anim) {
radius = (int) (5f / scale);
}
setRadius((int) DisplayUtil.dip2px(getContext(), radius));
//显示截图(添加圆角)
Glide.with(getContext())
.load(new File(path))
.transform(new CenterCrop(getContext()), new GlideRoundTransform(getContext(), radius))
.crossFade()
.listener(new RequestListener<File, GlideDrawable () {
@Override
public boolean onException(Exception e, File model, Target<GlideDrawable  target, boolean isFirstResource) {
if (anim) {
anim(thumb, true);
}
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, File model, Target<GlideDrawable  target, boolean isFromMemoryCache, boolean isFirstResource) {
if (thumb.getDrawable() == null) {
// 避免截图成功时出现短暂的全屏白色背景
thumb.setImageDrawable(resource);
}
if (anim) {
anim(thumb, true);
}
return false;
}
}).into(thumb);
//启动延时关闭截图(显示5秒消失截图)
startTick(true);
}
});
}
/**
* 动画设置
* @param view
* @param start
*/
private void anim(final ImageView view, boolean start) {
if (!start) {
if (getChildCount()   0) {
// 快速点击截图时,上一次添加的子视图尚未移除,需重置视图
resetView();
}
setScaleX(1f);
setScaleY(1f);
setTranslationX(0f);
setTranslationY(0f);
clearAnimation();
if (mScaleXAnim != null) {
mScaleXAnim.cancel();
mScaleXAnim = null;
}
if (mScaleYAnim != null) {
mScaleYAnim.cancel();
mScaleYAnim = null;
}
if (mTranslationXAnim != null) {
mTranslationXAnim.cancel();
mTranslationXAnim = null;
}
if (mTranslationYAnim != null) {
mTranslationYAnim.cancel();
mTranslationYAnim = null;
}
return;
}
view.post(new Runnable() {
@Override
public void run() {
if (!view.isAttachedToWindow()) {
// 子视图已被移除
return;
}
setCardBackgroundColor(Color.WHITE);
//等待cross fade动画
float margins = DisplayUtil.dip2px(getContext(), 10);
float scaleToX = (float) mFinalW / getMeasuredWidth();
float scaleToY = (float) mFinalH / getMeasuredHeight();
float translateToX = -(getMeasuredWidth() / 2f - (mFinalW / 2 + margins));
float translateToY = getMeasuredHeight() / 2f - (mFinalH / 2f + margins);
//以当前view为中心,x轴右为正,左为负;y轴下为正,上为负
mScaleXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleX", 1.0f, scaleToX);
mScaleYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "scaleY", 1.0f, scaleToY);
mTranslationXAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationX", 1.0f, translateToX);
mTranslationYAnim = ObjectAnimator.ofFloat(ScreenshotNotifyView.this, "translationY", 1.0f, translateToY);
//设置速度
mScaleXAnim.setDuration(500);
mScaleYAnim.setDuration(500);
mTranslationXAnim.setDuration(500);
mTranslationYAnim.setDuration(500);
//缩放
mScaleXAnim.start();
mScaleYAnim.start();
//平移
mTranslationXAnim.start();
mTranslationYAnim.start();
setEnabled(false);
mScaleXAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationCancel(Animator animation) {
super.onAnimationCancel(animation);
setEnabled(true);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
setEnabled(true);
setClickable(true);
}
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
});
}
});
}
private void resetView() {
setCardBackgroundColor(Color.TRANSPARENT);
removeAllViews();
startTick(false);
}
private void startTick(boolean start) {
if (!start) {
mHandler.removeCallbacksAndMessages(null);
return;
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
setVisibility(GONE);
}
}, 5 * 1000);
}
}

GlideRoundTransform.java

代码语言:javascript
复制
package com.lyw.myproject.screenshot;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
/**
* Created on 2018/12/26.
*
* @author lyw
**/
public class GlideRoundTransform extends BitmapTransformation {
private static float radius = 0f;
/**
* 构造函数 默认圆角半径 4dp
*
* @param context Context
*/
public GlideRoundTransform(Context context) {
this(context, 4);
}
/**
* 构造函数
*
* @param context Context
* @param dp 圆角半径
*/
public GlideRoundTransform(Context context, int dp) {
super(context);
radius = Resources.getSystem().getDisplayMetrics().density * dp;
}
@Override
protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
return roundCrop(pool, toTransform);
}
private static Bitmap roundCrop(BitmapPool pool, Bitmap source) {
if (source == null) {
return null;
}
Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
if (result == null) {
result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
}
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setShader(new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
paint.setAntiAlias(true);
RectF rectF = new RectF(0f, 0f, source.getWidth(), source.getHeight());
canvas.drawRoundRect(rectF, radius, radius, paint);
return result;
}
@Override
public String getId() {
return getClass().getName() + Math.round(radius);
}
}

activity_screen_shot1.xml

代码语言:javascript
复制
<?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="match_parent"
android:orientation="vertical" 
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" 
<ImageView
android:id="@+id/pic_iv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@mipmap/picture" / 
<com.lyw.myproject.widget.ScreenshotNotifyView
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/display_screenshot_snv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:cardBackgroundColor="@color/src_trans" / 
</FrameLayout 
<Button
android:id="@+id/screen_btn"
android:text="截图"
android:layout_gravity="center"
android:layout_marginTop="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/ 
</LinearLayout 

ScreenShotActivity1.java

代码语言:javascript
复制
package com.lyw.myproject.screenshot;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.Toast;
import com.lyw.myproject.BaseActivity;
import com.lyw.myproject.R;
import com.lyw.myproject.utils.LoadingLayout;
import com.lyw.myproject.utils.MemoryUtils;
import com.lyw.myproject.utils.PermissionUtil;
import com.lyw.myproject.widget.ScreenshotNotifyView;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import androidx.annotation.Nullable;
/**
* 功能描述:截图
*/
public class ScreenShotActivity1 extends BaseActivity {
private ImageView picImg;
private Button screenBtn;
private ScreenshotNotifyView mDisplayScreenshotSnv;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_screen_shot1);
initView();
initEvent();
}
private void initView() {
picImg = (ImageView) findViewById(R.id.pic_iv);
mDisplayScreenshotSnv = (ScreenshotNotifyView) findViewById(R.id.display_screenshot_snv);
screenBtn = (Button) findViewById(R.id.screen_btn);
}
private void initEvent() {
screenBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
handleScreenShot();
}
});
}
/**
* 处理截屏的业务
*/
private void handleScreenShot() {
if (!PermissionUtil.isHasSDCardWritePermission(this)) {
Toast.makeText(ScreenShotActivity1.this, "没有权限", Toast.LENGTH_SHORT).show();
PermissionUtil.requestSDCardWrite(this);
return;
}
if (!MemoryUtils.hasEnoughMemory(MemoryUtils.MIN_MEMORY)) {
Toast.makeText(ScreenShotActivity1.this, "内存不足,截图失败", Toast.LENGTH_SHORT).show();
return;
}
String filePath = getFilePath();
mDisplayScreenshotSnv.setVisibility(View.GONE);
mDisplayScreenshotSnv.setPath(filePath, picImg.getMeasuredWidth(), picImg.getMeasuredHeight(), true);
mDisplayScreenshotSnv.setVisibility(View.VISIBLE);
}
private String getFilePath() {
Bitmap bitmap = createViewBitmap(picImg);
if (bitmap != null) {
try {
// 首先保存图片
String storePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "HIS";
File appDir = new File(storePath);
if (!appDir.exists()) {
appDir.mkdir();
}
String fileName = System.currentTimeMillis() + ".jpg";
File file = new File(appDir, fileName);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
sendBroadcast(intent);
return file.getAbsolutePath();
} catch (Exception e) {
return null;
}
} else {
return null;
}
}
public Bitmap createViewBitmap(View v) {
Bitmap bitmap = Bitmap.createBitmap(v.getWidth(), v.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
v.draw(canvas);
return bitmap;
}
}

PermissionUtil.java

代码语言:javascript
复制
package com.lyw.myproject.utils;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import androidx.core.app.ActivityCompat;
public class PermissionUtil {
/**
* 请求地理位置
*
* @param context
*/
public static void requestLocationPermission(Context context) {
if (Build.VERSION.SDK_INT  = 23) {
if (!isHasLocationPermission(context)) {
ActivityCompat.requestPermissions((Activity) context, PermissionManager.PERMISSION_LOCATION, PermissionManager.REQUEST_LOCATION);
}
}
}
/**
* 判断是否有地理位置
*
* @param context
* @return
*/
public static boolean isHasLocationPermission(Context context) {
return ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
}
/**
* 判断是否有文件读写的权限
*
* @param context
* @return
*/
public static boolean isHasSDCardWritePermission(Context context) {
return ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED;
}
/**
* 文件权限读写
*
* @param context
*/
public static void requestSDCardWrite(Context context) {
if (Build.VERSION.SDK_INT  = 23) {
if (!isHasSDCardWritePermission(context)) {
ActivityCompat.requestPermissions((Activity) context, PermissionManager.PERMISSION_SD_WRITE, PermissionManager.REQUEST_SD_WRITE);
}
}
}
}

MemoryUtils.java

代码语言:javascript
复制
package com.lyw.myproject.utils;
import android.util.Log;
public class MemoryUtils {
public static final int MIN_MEMORY = 50 * 1024 * 1024;
/**
* 判断有没足够内存截图
*
* @param size
* @return
*/
public static boolean hasEnoughMemory(int size) {
//最大内存
long maxMemory = Runtime.getRuntime().maxMemory();
//分配的可用内存
long freeMemory = Runtime.getRuntime().freeMemory();
//已用内存
long usedMemory = Runtime.getRuntime().totalMemory() - freeMemory;
//剩下可使用的内存
long canUseMemory = maxMemory - usedMemory;
Log.d("Memory", "hasEnoughMemory: " +
"maxMemory = " + maxMemory +
", freeMemory = " + freeMemory +
", usedMemory = " + usedMemory +
", canUseMemory = " + canUseMemory);
if (canUseMemory  = size) {
return true;
}
return false;
}
}

总结

到此这篇关于android实现截图并动画消失的文章就介绍到这了,更多相关android实现截图并动画消失内容请搜索ZaLou.Cn以前的文章或继续浏览下面的相关文章希望大家以后多多支持ZaLou.Cn!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档