從零開始開發Android相機app(三)簡單介紹影象濾鏡功能
目前章節
1.從零開始安卓端相機功能開發(一)瞭解用什麼去開發以及流程
2.從零開始安卓端相機功能開發(二)讓我們來開發一個相機
3.從零開始開發Android相機app(三)簡單介紹影象濾鏡功能
原始碼地址:https://github.com/307572384/GPItest/commit/a89a605cec14bd573cd90994c973cfdd00f97991?diff=unified
1. 前期基礎知識詳解
濾鏡;主要是用來實現影象的各種特殊效果。它在Photoshop中具有非常神奇的作用。所有的濾鏡在Photoshop中都按分類放置在選單中,使用時只需要從該選單中執行這命令即可。濾鏡的操作是非常簡單的,但是真正用起來卻很難恰到好處。濾鏡通常需要同通道、圖層等聯合使用,才能取得最佳藝術效果。如果想在最適當的時候應用濾鏡到最適當的位置,除了平常的美術功底之外,還需要使用者對濾鏡的熟悉和操控能力,甚至需要具有很豐富的想象力。這樣,才能有的放矢的應用濾鏡,發揮出藝術才華。
以上來源於百度百科,當然我們的Android相機開發的影象濾鏡也不是那麼簡單的需要自己有一些動手能力和一定的英語閱讀水平和數學能力才能夠熟悉的一些東西,這裡我個人建議要想變得更強英語和數學這兩個要變得非常強才可以,畢竟有些外國文章寫得非常不錯可以用來參考,但是翻譯卻很少所以得提高自己的能力才行。這個是我這幾天的學習感受。
2.濾鏡效果如何實現分析
首先我們寫濾鏡效果可以使用現成的如GPUImage或者是其他的現成付費SDK也可以自己寫當然這種的話就比較麻煩涉及到演算法之類的,我個人比較推薦GPUImage這一款開源專案。
GPUImage 是iOS下一個開源的基於GPU的影象處理庫,提供各種各樣的影象處理濾鏡,並且支援照相機和攝像機的實時濾鏡。GPUImage for Android是它在Android下的實現,同樣也是開源的。其中提供了幾十多種常見的圖片濾鏡API,且其機制是基於GPU渲染,處理速度相應也比較快,是一個不錯的圖片實時處理框架。
而且現在還在更新狀態中。
需要的可以去看看GPUImageGithub開源專案
濾鏡處理物件:通常分為兩類:1.靜態圖片;2.實時相機預覽;3.視訊新增濾鏡;
實現方式有多種,比如通過呼叫Android系統提供的影象處理API,可以設定圖片的色調、飽和度、亮度,也可以呼叫ColorMatrix進行更加精確的圖片色彩調控,還可以使用更加精細化的畫素處理方式—提取圖片畫素點,然後對每個畫素點進行處理,使圖片變換不同的色彩效果,以上的方式都是呼叫Android系統提供的API進行處理,難點在於影象處理演算法的研究,這也是專業影象處理人員的工作之一,嘗試不同色彩矩陣的配合,可以建立出不同的色彩效果。
GPUImage是iOS的一個開源庫,後來也有了Android的版本,可以實現五十多種的濾鏡效果,不用開發者自己進行濾鏡演算法的實現,處理起來更加的方便,而且GPUImage可以做到的不僅僅是像ColorMatrix一樣的色彩特效,還可以進一步實現美顏相機需要的其他特效,比如磨皮,美白等,功能會更加強大。
3.我們來實現靜態的濾鏡實現吧
環境搭建
首先,要使用這個庫自然是要先匯入依賴,在app的gradle檔案中新增:
repositories {
google()
jcenter()
}
dependencies {
compile 'jp.co.cyberagent.android.gpuimage:gpuimage-library:1.4.1'
}
至於怎麼建立Assets檔案我們就使用這個
Android影象濾鏡框架GPUImage從配置到應用
然後裡面的素材圖片大家可以隨便寫一個然後匯入進去。
4.GPUImage API呼叫:
GPUImage主要通過一個GPUImageFilter類來提供各種濾鏡效果實現類,比如我們來實現一個將圖片變成的魚眼的濾鏡:
“GPUImageBulgeDistortionFilter” 【凸起失真,魚眼效果】這個是我們需要實現的效果。
我們來看一下魚眼效果
這裡是靜態濾鏡的MainActivity裡面有濾鏡的主要功能:包括濾鏡顯示到螢幕上和拖拉調整圖片飽和度的功能
務必在AndroidManifest中先新增聯網許可權
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
import android.content.Intent;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.Image;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import junit.framework.Assert;
import java.io.IOException;
import java.io.InputStream;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.GPUImageBulgeDistortionFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter;
import jp.co.cyberagent.android.gpuimage.GPUImageSaturationFilter;
public class MainActivity extends AppCompatActivity {
private GPUImage gpuImage;
//顯示處理結果
private ImageView resultIv;
//進度條
private SeekBar seekBar;
private Button bt_net;//點選跳轉到圖片網路濾鏡轉換
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
resultIv = (ImageView)findViewById(R.id.resultIv);
bt_net=(Button)findViewById(R.id.button) ;
seekBar = (SeekBar)this.findViewById(R.id.seekbar);
seekBar.setMax(10);
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
//通過進度條的值更改飽和度
resultIv.setImageBitmap(getGPUImageFromAssets(progress));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
//初始化圖片
resultIv.setImageBitmap(getGPUImageFromAssets(0));
bt_net.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this,NetActivity.class);
startActivity(intent);
}
});
}
//根據傳進來的數值設定素材飽和度
public Bitmap getGPUImageFromAssets(int progress)
{
//獲得Assets資原始檔
AssetManager as = getAssets();
InputStream is = null;
Bitmap bitmap = null;
try{
is = as.open("link.jpg");
bitmap = BitmapFactory.decodeStream(is);
is.close();
}catch (IOException e)
{
Log.e("GPUImage","Error");
}
gpuImage = new GPUImage(this);
gpuImage.setImage(bitmap);
gpuImage.setFilter(new GPUImageBulgeDistortionFilter());
bitmap = gpuImage.getBitmapWithFilterApplied();
//顯示處理圖片後的照片
return bitmap;
}
}
PS:這裡注意一下有些濾鏡功能是沒有飽和度如魚眼功能
這裡是MainActivity的activity_layout佈局檔案
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.beta.gpitest.MainActivity">
<ImageView
android:id="@+id/resultIv"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_gravity="center_vertical"
android:layout_marginBottom="23dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="93dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="跳轉到網路圖片濾鏡效果"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/resultIv" />
<Button
android:id="@+id/setting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="2dp"
android:text="setting"
app:layout_constraintBaseline_toBaselineOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent" />
</android.support.constraint.ConstraintLayout>
如果我們需要聯網進行濾鏡效果的話,由於訪問網路圖片,所以需要放在子執行緒中進行,所以這裡通過AsynTask(Android非同步執行緒,不清楚的可以看下這篇文章AsynTask使用簡介),現在子執行緒請求完網路圖片並轉換為Bitmap傳遞給主執行緒中對圖片進行濾鏡處理並顯示出來。
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import jp.co.cyberagent.android.gpuimage.GPUImage;
import jp.co.cyberagent.android.gpuimage.GPUImageGrayscaleFilter;
public class NetActivity extends AppCompatActivity {
private GPUImage gpuImage;
//顯示處理結果
private ImageView resultIv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.net_main);
resultIv = (ImageView) findViewById(R.id.imagex);
//開啟非同步執行緒載入圖片並處理
MyAsynTask asynTask = new MyAsynTask();
asynTask.execute();
}
class MyAsynTask extends AsyncTask<Integer,Integer,Bitmap>{
@Override
protected Bitmap doInBackground(Integer... params) {
//寫入圖片的url
Bitmap bitmap = getGPUImageFromURL("https://img-blog.csdn.net/20180422104130848?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MTEwMTE3Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70");
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
// 使用GPUImage處理影象
gpuImage = new GPUImage(getApplicationContext());
gpuImage.setImage(bitmap);
gpuImage.setFilter(new GPUImageGrayscaleFilter());
bitmap = gpuImage.getBitmapWithFilterApplied();
//顯示處理後的圖片儲存到bitmap
resultIv.setImageBitmap(bitmap);
}
}
public static Bitmap getGPUImageFromURL(String url) {
Bitmap bitmap = null;
try {
URL iconUrl = new URL(url);
URLConnection conn = iconUrl.openConnection();
HttpURLConnection http = (HttpURLConnection) conn;
int length = http.getContentLength();
conn.connect();
// 獲得影象的字元流
InputStream is = conn.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is, length);
bitmap = BitmapFactory.decodeStream(bis);
bis.close();
is.close();// 關閉流
} catch (Exception e) {
e.printStackTrace();
}
return bitmap;
}
}
網路圖片的layout這個很簡單就只是一個imageview:
<?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">
<ImageView
android:id="@+id/imagex"
android:layout_width="match_parent"
android:layout_height="229dp"
android:layout_gravity="center_horizontal" />
</LinearLayout>
5.最後叨一叨:
這個靜態濾鏡和聯網濾鏡功能已經實現了,接下來我需要做的是實現人臉識別美顏+組合濾鏡功能,不知道大家有沒有學習過或者使用過lightroom這款濾鏡調整的WIN平臺下的軟體因為我本身副職業是走的是攝影這條路所以有所學習到,但是我認為GpuImage的濾鏡功能就我暫時學到的可能有點少所以想要實現像LightRoom的那些大片濾鏡功能就稍微有些複雜不過還是慢慢的一步一步走下去比較好一點。
下面我們來看看我們走到哪一步了。
6.下面附上一些常用的濾鏡
Coloradjustments: 31 filters, 顏色處理相關
#import "GPUImageBrightnessFilter.h" //亮度
#import "GPUImageExposureFilter.h" //曝光
#import "GPUImageContrastFilter.h" //對比度
#import "GPUImageSaturationFilter.h" //飽和度
#import "GPUImageGammaFilter.h" //伽馬線
#import "GPUImageColorInvertFilter.h" //反色
#import "GPUImageSepiaFilter.h" //褐色(懷舊)
#import "GPUImageLevelsFilter.h" //色階
#import "GPUImageGrayscaleFilter.h" //灰度
#import "GPUImageHistogramFilter.h" //色彩直方圖,顯示在圖片上
#import "GPUImageHistogramGenerator.h" //色彩直方圖
#import "GPUImageRGBFilter.h" //RGB
#import "GPUImageToneCurveFilter.h" //色調曲線
#import "GPUImageMonochromeFilter.h" //單色
#import "GPUImageOpacityFilter.h" //不透明度
#import "GPUImageHighlightShadowFilter.h" //提亮陰影
#import "GPUImageFalseColorFilter.h" //色彩替換(替換亮部和暗部色彩)
#import "GPUImageHueFilter.h" //色度
#import "GPUImageChromaKeyFilter.h" //色度鍵
#import "GPUImageWhiteBalanceFilter.h" //白平橫
#import "GPUImageAverageColor.h" //畫素平均色值
#import "GPUImageSolidColorGenerator.h" //純色
#import "GPUImageLuminosity.h" //亮度平均
#import "GPUImageAverageLuminanceThresholdFilter.h" //畫素色值亮度平均,影象黑白(有類似漫畫效果)
#import "GPUImageLookupFilter.h" //lookup 色彩調整
#import "GPUImageAmatorkaFilter.h" //Amatorka lookup
#import "GPUImageMissEtikateFilter.h" //MissEtikate lookup
#import "GPUImageSoftEleganceFilter.h" //SoftElegance lookup
**#pragma mark - 影象處理 Handle Image**
Image processing: 40 filters, 影象處理相關.
#import "GPUImageCrosshairGenerator.h" //十字
#import "GPUImageLineGenerator.h" //線條
#import "GPUImageTransformFilter.h" //形狀變化
#import "GPUImageCropFilter.h" //剪裁
#import "GPUImageSharpenFilter.h" //銳化
#import "GPUImageUnsharpMaskFilter.h" //反遮罩銳化
//#import "GPUImageFastBlurFilter.h" //模糊
#import "GPUImageGaussianBlurFilter.h" //高斯模糊
#import "GPUImageGaussianSelectiveBlurFilter.h" //高斯模糊,選擇部分清晰
#import "GPUImageBoxBlurFilter.h" //盒狀模糊
#import "GPUImageTiltShiftFilter.h" //條紋模糊,中間清晰,上下兩端模糊
#import "GPUImageMedianFilter.h" //中間值,有種稍微模糊邊緣的效果
#import "GPUImageBilateralFilter.h" //雙邊模糊
#import "GPUImageErosionFilter.h" //侵蝕邊緣模糊,變黑白
#import "GPUImageRGBErosionFilter.h" //RGB侵蝕邊緣模糊,有色彩
#import "GPUImageDilationFilter.h" //擴充套件邊緣模糊,變黑白
#import "GPUImageRGBDilationFilter.h" //RGB擴充套件邊緣模糊,有色彩
#import "GPUImageOpeningFilter.h" //黑白色調模糊
#import "GPUImageRGBOpeningFilter.h" //彩色模糊
#import "GPUImageClosingFilter.h" //黑白色調模糊,暗色會被提亮
#import "GPUImageRGBClosingFilter.h" //彩色模糊,暗色會被提亮
#import "GPUImageLanczosResamplingFilter.h" //Lanczos重取樣,模糊效果
#import "GPUImageNonMaximumSuppressionFilter.h" //非最大抑制,只顯示亮度最高的畫素,其他為黑
#import "GPUImageThresholdedNonMaximumSuppressionFilter.h" //與上相比,畫素丟失更多
#import "GPUImageSobelEdgeDetectionFilter.h" //Sobel邊緣檢測演算法(白邊,黑內容,有點漫畫的反色效果)
#import "GPUImageCannyEdgeDetectionFilter.h" //Canny邊緣檢測演算法(比上更強烈的黑白對比度)
#import "GPUImageThresholdEdgeDetectionFilter.h" //閾值邊緣檢測(效果與上差別不大)
#import "GPUImagePrewittEdgeDetectionFilter.h" //普瑞維特(Prewitt)邊緣檢測(效果與Sobel差不多,貌似更平滑)
#import "GPUImageXYDerivativeFilter.h" //XYDerivative邊緣檢測,畫面以藍色為主,綠色為邊緣,帶彩色
#import "GPUImageHarrisCornerDetectionFilter.h" //Harris角點檢測,會有綠色小十字顯示在圖片角點處
#import "GPUImageNobleCornerDetectionFilter.h" //Noble角點檢測,檢測點更多
#import "GPUImageShiTomasiFeatureDetectionFilter.h" //ShiTomasi角點檢測,與上差別不大
#import "GPUImageMotionDetector.h" //動作檢測
#import "GPUImageHoughTransformLineDetector.h" //線條檢測
#import "GPUImageParallelCoordinateLineTransformFilter.h" //平行線檢測
#import "GPUImageLocalBinaryPatternFilter.h" //影象黑白化,並有大量噪點
#import "GPUImageLowPassFilter.h" //用於影象加亮
#import "GPUImageHighPassFilter.h" //影象低於某值時顯示為黑
#pragma mark - 視覺效果 Visual Effect
Visual effects: 25 filters, 視覺效果相關
#import "GPUImageSketchFilter.h" //素描
#import "GPUImageThresholdSketchFilter.h" //閥值素描,形成有噪點的素描
#import "GPUImageToonFilter.h" //卡通效果(黑色粗線描邊)
#import "GPUImageSmoothToonFilter.h" //相比上面的效果更細膩,上面是粗曠的畫風
#import "GPUImageKuwaharaFilter.h" //桑原(Kuwahara)濾波,水粉畫的模糊效果;處理時間比較長,慎用
#import "GPUImageMosaicFilter.h" //黑白馬賽克
#import "GPUImagePixellateFilter.h" //畫素化
#import "GPUImagePolarPixellateFilter.h" //同心圓畫素化
#import "GPUImageCrosshatchFilter.h" //交叉線陰影,形成黑白網狀畫面
#import "GPUImageColorPackingFilter.h" //色彩丟失,模糊(類似監控攝像效果)
#import "GPUImageVignetteFilter.h" //暈影,形成黑色圓形邊緣,突出中間影象的效果
#import "GPUImageSwirlFilter.h" //漩渦,中間形成捲曲的畫面
#import "GPUImageBulgeDistortionFilter.h" //凸起失真,魚眼效果
#import "GPUImagePinchDistortionFilter.h" //收縮失真,凹面鏡
#import "GPUImageStretchDistortionFilter.h" //伸展失真,哈哈鏡
#import "GPUImageGlassSphereFilter.h" //水晶球效果
#import "GPUImageSphereRefractionFilter.h" //球形折射,圖形倒立
#import "GPUImagePosterizeFilter.h" //色調分離,形成噪點效果
#import "GPUImageCGAColorspaceFilter.h" //CGA色彩濾鏡,形成黑、淺藍、紫色塊的畫面
#import "GPUImagePerlinNoiseFilter.h" //柏林噪點,花邊噪點
#import "GPUImage3x3ConvolutionFilter.h" //3x3卷積,高亮大色塊變黑,加亮邊緣、線條等
#import "GPUImageEmbossFilter.h" //浮雕效果,帶有點3d的感覺
#import "GPUImagePolkaDotFilter.h" //畫素圓點花樣
#import "GPUImageHalftoneFilter.h" //點染,影象黑白化,由黑點構成原圖的大致圖形
#pragma mark - 混合模式 Blend
Blending modes: 29 filters, 混合模式相關.
#import "GPUImageMultiplyBlendFilter.h" //通常用於建立陰影和深度效果
#import "GPUImageNormalBlendFilter.h" //正常
#import "GPUImageAlphaBlendFilter.h" //透明混合,通常用於在背景上應用前景的透明度
#import "GPUImageDissolveBlendFilter.h" //溶解
#import "GPUImageOverlayBlendFilter.h" //疊加,通常用於建立陰影效果
#import "GPUImageDarkenBlendFilter.h" //加深混合,通常用於重疊型別
#import "GPUImageLightenBlendFilter.h" //減淡混合,通常用於重疊型別
#import "GPUImageSourceOverBlendFilter.h" //源混合
#import "GPUImageColorBurnBlendFilter.h" //色彩加深混合
#import "GPUImageColorDodgeBlendFilter.h" //色彩減淡混合
#import "GPUImageScreenBlendFilter.h" //螢幕包裹,通常用於建立亮點和鏡頭眩光
#import "GPUImageExclusionBlendFilter.h" //排除混合
#import "GPUImageDifferenceBlendFilter.h" //差異混合,通常用於建立更多變動的顏色
#import "GPUImageSubtractBlendFilter.h" //差值混合,通常用於建立兩個影象之間的動畫變暗模糊效果
#import "GPUImageHardLightBlendFilter.h" //強光混合,通常用於建立陰影效果
#import "GPUImageSoftLightBlendFilter.h" //柔光混合
#import "GPUImageChromaKeyBlendFilter.h" //色度鍵混合
#import "GPUImageMaskFilter.h" //遮罩混合
#import "GPUImageHazeFilter.h" //朦朧加暗
#import "GPUImageLuminanceThresholdFilter.h" //亮度閾
#import "GPUImageAdaptiveThresholdFilter.h" //自適應閾值
#import "GPUImageAddBlendFilter.h" //通常用於建立兩個影象之間的動畫變亮模糊效果
#import "GPUImageDivideBlendFilter.h" //通常用於建立兩個影象之間的動畫變暗模糊效果
本文參考自:
Android影象濾鏡框架GPUImage從配置到應用
Android使用GPUImage實現濾鏡效果精煉詳解(一)
相關文章
- 【FFmpeg筆記】 從零開始之濾鏡筆記
- 從零開始:如何使用美顏濾鏡SDK開發出高質量的應用
- 從零開始完成一個Android JNI開發Android
- 《Python深度學習從零開始學》簡介Python深度學習
- uni-app 小程式從零開始的開發流程APP
- 《谷歌JAX深度學習從零開始學》簡介谷歌深度學習
- 《Django 3 Web應用開發從零開始學(影片教學版)》簡介DjangoWeb
- 從零開始仿寫一個抖音App——開始APP
- 從零開始的簡單光線追蹤示例
- Android從零開始(第三篇)MVP架構搭建AndroidMVP架構
- 從零開始發明 AC 自動機
- 【從零開始擼一個App】PKCEAPP
- 【從零開始擼一個App】KotlinAPPKotlin
- 如何從零開始整合DTM Android SDKAndroid
- 直播APP原始碼系統家族功能開發介紹APP原始碼
- 《HTML5+CSS3+JavaScript前端開發從零開始學(影片教學版)》簡介HTMLCSSS3JavaScript前端
- 從零開始開發一個 WebpackWeb
- 從零開始
- 從零開始機器學習機器學習
- 不怕從零開始,只怕從未開始!
- 從零開始學Electron筆記(三)筆記
- 簡單介紹python中的mock介面開發PythonMock
- 從零開始學前端動畫 —— 簡單的特效登入前端動畫特效
- 從零開始實現簡單 RPC 框架 4:註冊中心RPC框架
- 量化現貨合約跟單社群app軟體開發原始碼功能介紹APP原始碼
- 簡單介紹Android自定義View實現時鐘功能AndroidView
- 【從零開始擼一個App】Dagger2APP
- 從零開始,使用Dapr簡化微服務微服務
- Android開發之從零開始學RxJava 2.x(一)認識RxjavaAndroidRxJava
- 從零開始機器學習-03機器學習
- 從零開始機器學習--4機器學習
- 從零開始機器學習--05機器學習
- 從零開始React專案架構(三)React架構
- Android開發 - 掌握ConstraintLayout(二)介紹AndroidAI
- Kotlin on Android 開發環境介紹KotlinAndroid開發環境
- HarmonyOS三方件開發指南(15)-LoadingView功能介紹View
- 從零開始搭建本地 Docker 開發環境Docker開發環境
- 微信小程式從零開始開發步驟(三)底部導航欄微信小程式