GIF, APNG : SDWebImage 라이브러리 사용

 

SVG : SVGKit 라이브러리 사용

 

 

이미지는 앱 번들에 포함

 

 

  • GIF, APNG : ImageView 를 포함시켜 SDAnimatedImageView 클래스로 지정
  • SVG : UIView 를 포함시켜 SVGKFastImageView 클래스로 지정

 

 

ViewController.h

#import <UIKit/UIKit.h>
#import "SDWebImage/SDAnimatedImageView.h"
#import "SDWebImage/SDAnimatedImage.h"
#import "SVGKit.h"
#import "SVGKImage.h"
#import "SVGKFastImageView.h"
 
@interface ViewController : UIViewController
@property (strong, nonatomic) IBOutlet SDAnimatedImageView *imgGif;
@property (strong, nonatomic) IBOutlet SVGKFastImageView *imgSvg;
@property (strong, nonatomic) IBOutlet SDAnimatedImageView *imgApng;
 
 
@end
cs

 

 

ViewController.m

@implementation ViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
 
    // GIF
    NSString *gifPath = [[NSBundle mainBundle] pathForResource:@"gif_sample" ofType:@"gif"];
    NSData *gifData = [NSData dataWithContentsOfFile:gifPath];
    [self.imgGif setImage:[SDAnimatedImage imageWithData:gifData]];
 
    // SVG
    SVGKImage *svgImage = [SVGKImage imageNamed:@"svg_sample.svg"];
    [self.imgSvg setImage:svgImage];
    
    // APNG
    NSString *apngPath = [[NSBundle mainBundle] pathForResource:@"apng_sample" ofType:@"png"];
    NSData *apngData = [NSData dataWithContentsOfFile:apngPath];
    [self.imgApng setImage:[SDAnimatedImage imageWithData:apngData]];
}
 
 
@end
 
cs
  • SVG 이미지 

프로젝트에서 마우스 우클릭
이미지 이름, 사이즈 설정

 

  • APNG 이미지

assets 폴더에 넣기

 

 

build.gradle.kts

    // gif - glide
    implementation("com.github.bumptech.glide:glide:4.16.0")
    annotationProcessor("com.github.bumptech.glide:compiler:4.16.0")
 
    // apng - penfeizhou
    implementation ("com.github.penfeizhou.android.animation:apng:3.0.4")
 
cs

 

 

MainActivity.java

public class MainActivity extends AppCompatActivity {
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        // GIF
        ImageView imgGif = findViewById(R.id.imgGif);
        Glide.with(this)
                .asGif()
                .load(R.drawable.gif_sample)
                .into(imgGif);
 
        // SVG
        ImageView imgSvg = findViewById(R.id.imgSvg);
        imgSvg.setImageResource(R.drawable.svg_sample);
 
        // APNG
        ImageView imgApng = findViewById(R.id.imgApng);
        AssetStreamLoader assetStreamLoader = new AssetStreamLoader(this"apng_sample.png");
        APNGDrawable apng = new APNGDrawable(assetStreamLoader);
        imgApng.setImageDrawable(apng);
    }
}
cs

 

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:gravity="center_horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <TextView
        android:text="GIF"
        android:layout_marginTop="24dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
    <ImageView
        android:id="@+id/imgGif"
        android:scaleType="fitCenter"
        android:layout_marginTop="12dp"
        android:layout_width="wrap_content"
        android:layout_height="100dp" />
 
    <TextView
        android:text="SVG"
        android:layout_marginTop="24dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
    <ImageView
        android:id="@+id/imgSvg"
        android:scaleType="fitCenter"
        android:layout_marginTop="12dp"
        android:layout_width="wrap_content"
        android:layout_height="100dp" />
 
    <TextView
        android:text="APNG"
        android:layout_marginTop="24dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
    <ImageView
        android:id="@+id/imgApng"
        android:scaleType="fitCenter"
        android:layout_marginTop="12dp"
        android:layout_width="wrap_content"
        android:layout_height="100dp" />
 
</LinearLayout>
cs

 

 

결과

 

* 물이 하나도 채워지지 않은 (progress 가 0) 이미지 ic_water_empty.png 와 물이 모두 채워진 (progress 가 100) 이미지 ic_water_full.png 가 필요

 

 

#import "ViewController.h"
 
@interface ViewController ()
// 마스크뷰 - 물이 위로 차오르는 효과를 주기 위해
@property (nonatomic, strong) UIView *maskView;
 
@end
 
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
 
    // 물이 빈 이미지
    self.ivEmptyWater.contentMode = UIViewContentModeScaleAspectFit;
    // 물이 가득찬 이미지
    self.ivFullWater.contentMode = UIViewContentModeScaleAspectFit;
    
}
 
// 뷰의 사이즈가 정해진 후 여러번 호출될 수 있음
- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
    
    if(!self.maskView) {
        [self setUpMaskView];
    }
}
 
- (void) setUpMaskView {
    // 물이 가득찬 이미지뷰에 마스크뷰 설정 - 마스크뷰가 올라가면서 물이 점점 차오르는 애니메이션을 줄 수 있다
    self.maskView = [[UIView alloc] initWithFrame:CGRectMake(0self.ivFullWater.bounds.size.height, self.ivFullWater.bounds.size.width, 0)];
    self.maskView.backgroundColor = UIColor.blackColor;
    self.ivFullWater.layer.mask = self.maskView.layer;
}
 
- (IBAction)onStart:(UIButton *)sender {
    // ex) 80% 까지 물이 채워짐
    [self updateProgress:80];
}
 
// 프로그레스 업데이트 : progress - 0~100
- (void) updateProgress:(NSInteger)progress {
    progress = MAX(0, MIN(progress, 100));
    
    CGFloat maxHeight = self.ivFullWater.bounds.size.height;
    CGFloat maskHeight = maxHeight * (progress / 100.0);    // progress 만큼 마스크뷰 높이 설정 ex) 80->전체 높이의 80% 만큼 설정
    CGFloat maskYPos = maxHeight - maskHeight;
    
    // 보여줄 영역을 설정 - 마스크뷰 영역만큼만 ivFullWater 를 보여준다
    CGRect maskFrame = CGRectMake(0, maskYPos, self.ivFullWater.bounds.size.width, maskHeight);
    
    // 2초 애니메이션 실행
    [UIView animateWithDuration:2.0 animations:^{
        self.maskView.frame = maskFrame;
    }];
}
 
@end
 
cs

 

 

스토리보드

 

 

결과

 

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
[IOS] PDF 문서 보기 - WKWebView 사용  (0) 2025.05.11
[IOS] PDF 문서 보기 - PDFKit 사용  (0) 2025.05.10

* 물이 하나도 채워지지 않은 (progress 가 0) 이미지 ic_water_empty.png 와 물이 모두 채워진 (progress 가 100) 이미지 ic_water_full.png 가 필요

 

 

MainActivity.java

public class MainActivity extends AppCompatActivity {
 
    // progress 만큼 물이 채워지는 애니메이션
    private ValueAnimator mAnimation = new ValueAnimator();
    // 프로그레스를 보여줄 뷰
    FrameLayout progressBar;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        progressBar = findViewById(R.id.progressBar);
        Button btnStart = findViewById(R.id.btnStart);
        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // ex) 80% 까지 물이 채워짐
                updateProgress(80);
            }
        });
 
        // 애니메이션
        mAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) {
                // 애니메이션 프레임마다 호출 - 배경 drawable의 level 만큼 위로 차오른다
                progressBar.getBackground().setLevel((Integer) valueAnimator.getAnimatedValue());
            }
        });
        mAnimation.setDuration(2000);
    }
 
    // 프로그레스 업데이트 : progress - 0~100
    private void updateProgress(int progress) {
        progress = Math.max(0, progress);
        progress = Math.min(progress, 100);
        // ClipDrawable은 0~10000 사이의 level 값
        int level = (int) Math.round((double) progress / 100 * 10000);
        // 0~level 값만큼 애니메이션 실행
        mAnimation.setIntValues(0, level);
        mAnimation.start();
    }
}
 
cs

 

 

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <FrameLayout
        android:id="@+id/progressBar"
        android:background="@drawable/progress_water"
        android:layout_centerInParent="true"
        android:layout_width="128dp"
        android:layout_height="128dp" />
 
    <Button
        android:id="@+id/btnStart"
        android:text="Start"
        android:layout_marginTop="24dp"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
</RelativeLayout>
cs

 

 

progress_water.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_water_empty" />
    <item android:drawable="@drawable/progress_water_clip" />
</layer-list>
cs

 

 

progress_water_clip.xml

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_water_full"
    android:clipOrientation="vertical"
    android:gravity="bottom">
</clip>
cs

 

 

결과

PdfRenderActivity.java

public class PdfRenderActivity extends AppCompatActivity {
 
    ViewPager2 mViewPager;
    PdfRenderAdapter mAdapter;
    List<Bitmap> mPageBitmaps = new ArrayList<>();
 
    PdfRenderer mRenderer;
    ParcelFileDescriptor mDescriptor;
 
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pdfrender);
        mViewPager = findViewById(R.id.viewPager);
 
 
        try {
            // Assets 폴더의 .pdf 파일 -> File 객체로 복사
            InputStream is = getAssets().open("SampleTest.pdf");
            File outFile = new File(getFilesDir(), "SampleTest.pdf");
            OutputStream os = new FileOutputStream(outFile);
 
            byte[] buffer = new byte[1024*1024];
            int length;
            while( (length = is.read(buffer)) > 0 ) {
                os.write(buffer, 0length);
            }
            os.flush();
            os.close();
            is.close();
 
 
            // PDF 파일을 Bitmap 으로 변환하여 뷰페이저로 보기
            // 파일을 읽기 모드로 open
            mDescriptor = ParcelFileDescriptor.open(outFile, ParcelFileDescriptor.MODE_READ_ONLY);
            // PdfRender 객체와 pdf 파일을 연결
            mRenderer = new PdfRenderer(mDescriptor);
 
            // 페이지수만큼 반복
            for ( int i = 0; i < mRenderer.getPageCount(); i++ ) {
                // 페이지 열기
                PdfRenderer.Page page = mRenderer.openPage(i);
                // pdf 페이지를 bitmap 으로 변환하여 사용자에게 보여주기
                Bitmap bitmap = Bitmap.createBitmap(page.getWidth(), page.getHeight(), Bitmap.Config.ARGB_8888);
                page.render(bitmap, nullnull, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);
 
                this.mPageBitmaps.add(bitmap);
                page.close();
            }
 
            // 뷰페이저로 보여주기
            mAdapter = new PdfRenderAdapter(this.mPageBitmaps);
            mViewPager.setAdapter(this.mAdapter);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
 
    @Override
    protected void onDestroy() {
        // 리소스 닫기
        try {
            if(mDescriptor != null) {
                mDescriptor.close();
            }
            if(mRenderer != null) {
                mRenderer.close();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
 
        super.onDestroy();
    }
}
cs

 

 

PdfRenderAdapter.java

public class PdfRenderAdapter extends RecyclerView.Adapter<PdfRenderAdapter.PdfRenderHolder> {
 
    private List<Bitmap> bitmaps;
 
    public PdfRenderAdapter(List<Bitmap> bitmaps) {
        this.bitmaps = bitmaps;
    }
 
 
    @NonNull
    @Override
    public PdfRenderHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_pdfrender, parent, false);
        return new PdfRenderHolder(view);
    }
 
    @Override
    public void onBindViewHolder(@NonNull PdfRenderHolder holder, int position) {
        holder.imageView.setImageBitmap(this.bitmaps.get(position));
    }
 
    @Override
    public int getItemCount() {
        return bitmaps.size();
    }
 
    static class PdfRenderHolder extends RecyclerView.ViewHolder {
        ImageView imageView;
 
        public PdfRenderHolder(@NonNull View itemView) {
            super(itemView);
            imageView = itemView.findViewById(R.id.imageView);
        }
    }
}
 
cs

 

 

activity_pdfrender.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</LinearLayout>
cs

 

 

item_pdfrender.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <ImageView
        android:id="@+id/imageView"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</LinearLayout>
cs

 

 

build.gradle.kts

    implementation ("androidx.viewpager2:viewpager2:1.1.0")
cs

 

 

결과

public class WebViewActivity extends AppCompatActivity {
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
 
        // 웹뷰 + 구글 Docs뷰어
        WebView webView = findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        // 인터넷에 있는 pdf 문서만 가능
        // 앱내 로컬에 있는 pdf 문서를 보기위해서는 라이브러리를 사용하여 로컬 웹서버로 url 호출해야 한다
        String pdfUrl = "https://www.navercorp.com/navercorp_/resource/Naver_Hands_Introduction_2023.pdf";
        webView.loadUrl("https://docs.google.com/gview?embedded=true&url=" + pdfUrl);
    }
}
 
cs

 

 

    <uses-permission android:name="android.permission.INTERNET" />
cs

 

 

결과

250

#import "WebViewController.h"
#import <WebKit/WebKit.h>
 
@interface WebViewController ()
 
@end
 
@implementation WebViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 번들에 있는 pdf 파일 가져오기
    NSString *path = [[NSBundle mainBundle] pathForResource:@"SampleTest" ofType:@"pdf"];
    NSURL *url = [NSURL fileURLWithPath:path];
    
    WKWebView *webView = [[WKWebView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:webView];
    
    // NSURLRequest 만든후 WKWebView 로 로드
    // 인터넷에 있는 PDF 파일도 동일하게 NSURLRequest 객체 생성 후 웹요청하여 사용
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [webView loadRequest:request];
}
 
@end
cs

 

 

결과

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
[IOS] 이미지로 프로그레스바 만들기  (0) 2025.05.17
[IOS] PDF 문서 보기 - PDFKit 사용  (0) 2025.05.10
#import "PdfViewController.h"
#import <PDFKit/PDFKit.h>
 
@interface PdfViewController ()
 
@end
 
@implementation PdfViewController
 
- (void)viewDidLoad {
    [super viewDidLoad];
    
    
    // 번들에 있는 pdf 파일 가져오기
    NSString *path = [[NSBundle mainBundle] pathForResource:@"SampleTest" ofType:@"pdf"];
    NSURL *url = [NSURL fileURLWithPath:path];
 
    // PDF문서
    PDFDocument *document = [[PDFDocument alloc] initWithURL:url];
    // PDF뷰
    PDFView *pdfView = [[PDFView alloc] initWithFrame:self.view.bounds];
    // PDF문서를 PDF뷰 크기에 맞게 자동 확대/축소
    pdfView.autoScales = YES;
    // PDF문서와 PDF뷰 연결
    pdfView.document = document;
 
    // 뷰 전체 화면에 추가
    pdfView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:pdfView];
}
 
@end
cs

 

 

결과

'IT > Ⅰ. IOS' 카테고리의 다른 글

[IOS] GIF, SVG, APNG 이미지 사용  (0) 2025.05.22
[IOS] 이미지로 프로그레스바 만들기  (0) 2025.05.17
[IOS] PDF 문서 보기 - WKWebView 사용  (0) 2025.05.11
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
 
    <com.github.barteksc.pdfviewer.PDFView
        android:id="@+id/pdfView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
 
</LinearLayout>
cs

 

 

public class PdfViewerActivity extends AppCompatActivity {
 
    PDFView mPDFView;
 
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pdfviewer);
 
        mPDFView = findViewById(R.id.pdfView);
        // assets 폴더에 있는 pdf 파일읽기
        mPDFView.fromAsset("SampleTest.pdf")
                .enableSwipe(true)      // 스와이프로 페이지 넘김
                .swipeHorizontal(false// true-가로로 넘김, false-세로로 넘김
                .enableDoubletap(true)  // 화면을 두번 탭하여 확대/축소
                .load();
 
    }
}
cs

 - assets폴더에 SampleTest.pdf 파일을 포함시키고 로드

 

 

implementation ("com.github.mhiew:android-pdf-viewer:3.2.0-beta.3")
 
cs

 

 

결과

 

전광판 앱은 개인정보를 수집하지 않습니다

전광판 앱은 로그인을 하지 않습니다

전광판 앱은 무료로 사용하실 수 있습니다

전광판 앱은 전 연령이 안전하게 사용하실 수 있습니다

 

[앱 관련 지원방법]

댓글 또는 메일로 문의 주시기 바랍니다

 

[개인정보처리방침]

전광판 앱은 개인정보를 요구하거나 저장하지 않습니다.

 

+ Recent posts