Android Picasso最詳細的使用指南

来源:https://www.cnblogs.com/jiangzhishan/archive/2018/08/03/9414141.html
-Advertisement-
Play Games

Picasso 是Square 公司開源的Android 端的圖片載入和緩存框架。Square 真是一家良心公司啊,為我們Android開發者貢獻了很多優秀的開源項目有木有!像什麼Rerefoit 、OkHttp、LeakCanary、Picasso等等都是非常火的開源項目。回到正題,除了使用簡單方 ...


Picasso 是Square 公司開源的Android 端的圖片載入和緩存框架。Square 真是一家良心公司啊,為我們Android開發者貢獻了很多優秀的開源項目有木有!像什麼Rerefoit 、OkHttp、LeakCanary、Picasso等等都是非常火的開源項目。回到正題,除了使用簡單方便,Picasso還能自動幫我們做以下事情:

  • 處理Adapter 中ImageView的回收和取消下載。
  • 使用最小的記憶體 來做複雜的圖片變換。比如高斯模糊,圓角、圓形等處理。
  • 自動幫我們緩存圖片。記憶體和磁碟緩存。

以上只是列出了Picasso 比較核心的幾點,其實它的優點遠遠不止這些,接下來就看一下如何使用Picasso。

                  Picasso-Android.png

本文目錄

0,添加依賴
1, 載入顯示圖片
2,Placeholder & noPlaceholder & noFade
3 , 設置圖片尺寸(Resize)、縮放(Scale)和裁剪(Crop)
4,圖片旋轉Rotation()
5 , 轉換器Transformation
6,請求優先順序
7,Tag管理請求
8,同步/非同步載入圖片
9,緩存(Disk 和 Memory)
10,Debug 和日誌
11,Picasso 擴展

正文

0. 添加依賴

要使用Picasso,首先我們要添加版本依賴,去官網或者Github 看一下當前的最新版本(截止本文最新版本為2.5.2),然後在build.gradle中添加依賴:

1. 載入顯示圖片

將Picasso添加到項目之後,我們就可以用它來載入圖片了,使用方法非常簡單:

只需要一行代碼就完成了載入圖片到顯示的整個過程,鏈式調用,非常簡潔,其實有三步,一次調用了三個方法:

  • with(Context) 獲取一個Picasso單例,參數是一個Context上下文
  • load(String) 調用load 方法載入圖片
  • into (ImageView) 將圖片顯示在對應的View上,可以是ImageView,也可以是實現了Target j介面的自定義View。

上面演示了載入一張網路圖片,它還支持其它形式的圖片載入,載入文件圖片,載入本地資源圖片,載入一個Uri 路徑給的圖片,提供了幾個重載的方法:

load(Uri uri) 載入一個以Uri路徑給的圖片

load(File file) 載入File中的圖片

load(int resourceId) 載入本地資源圖片

提醒:上面介紹了load的幾個重載方法,載入不同資源的圖片,另外提醒註意一下load(String path)接受String 參數的這個方法,參數String 可以是一個網路圖片url,也可以是file 路徑、content資源 和Android Resource。看一下源碼的註釋。

要使用string 參數載入上面的幾種資源,除了網路url,其它幾種需要加上對應首碼,file文件路徑首碼:file: , content 添加首碼:content: ,Android Resource 添加:android.resource:

2. placeholder& error & noPlaceholder & noFade

通過上面的第一步我們就可以通過Picasso 載入圖片了,我們的項目中通常最常用的就是載入網路圖片,但是由於網路環境的差異,有時侯載入網路圖片的過程有點慢,這樣界面上就會顯示空ImageView什麼也看不見,用戶體驗非常不好。其實以前用過ImageLoader的同學都知道,ImageLoader 是可以設置載入中顯示預設圖片的,Picasso當然也給我們提供了這個功能。

placeholder
placeholder提供一張在網路請求還沒有完成時顯示的圖片,它必須是本地圖片,代碼如下:

設置placeholder之後,在載入圖片的時候,就可以顯示設置的預設圖了,提升用戶體驗。
error
和placeholder 的用法一樣,error 提供一張在載入圖片出錯的情況下顯示的預設圖

noPlaceholder
這個方法的意思就是:在調用into的時候明確告訴你沒有占點陣圖設置。根據這個方法簽名的解釋是阻止View被回收的時候Picasso清空target或者設置一個應用的占點陣圖。需要註意的是placeholder和noPlaceholder 不能同時應用在同一個請求上,會拋異常。

noFade
無論你是否設置了占點陣圖,Picasso 從磁碟或者網路載入圖片時,into 顯示到ImageView 都會有一個簡單的漸入過度效果,讓你的UI視覺效果更柔順絲滑一點,如果你不要這個漸入的效果,就調用noFade方法。

3. 設置圖片尺寸(Resize)、縮放(Scale)和裁剪(Crop)

Resize(int w,int h)
在項目中,為了帶寬、記憶體使用和下載速度等考慮,服務端給我們的圖片的size 應該和我們View 實際的size一樣的,但是實際情況並非如此,服務端可能給我們一些奇怪的尺寸的圖片,我們可以使用resize(int w,int hei) 來重新設置尺寸。

resize()方法接受的參數的單位是pixels,還有一個可以設置dp單位的方法,將你的尺寸寫在dimens.xml文件中,然後用resizeDimen(int targetWidthResId, int targetHeightResId)方法

onlyScaleDown
當調用了resize 方法重新設置圖片尺寸的時候,調用onlyScaleDown 方法,只有當原始圖片的尺寸大於我們指定的尺寸時,resize才起作用,如:

只有當原來的圖片尺寸大於4000 x 2000的時候,resize 才起作用。
圖片裁剪 centerCrop()
這個屬性應該不陌生吧!ImageView 的ScaleType 就有這個屬性。當我們使用resize 來重新設置圖片的尺寸的時候,你會發現有些圖片拉伸或者扭曲了(使用ImageView的時候碰到過吧),我要避免這種情況,Picasso 同樣給我們提供了一個方法,centerCrop,充滿ImageView 的邊界,居中裁剪。

centerInside
上面的centerCrop是可能看不到全部圖片的,如果你想讓View將圖片展示完全,可以用centerInside,但是如果圖片尺寸小於View尺寸的話,是不能充滿View邊界的。

fit
fit 是乾什的呢?上面我們需要用resize()來指定我們需要的圖片的尺寸,那就是說在程式中需要我們計算我們需要的尺寸(固定大小的除外),這樣很麻煩,fit 方法就幫我們解決了這個問題。fit 它會自動測量我們的View的大小,然後內部調用reszie方法把圖片裁剪到View的大小,這就幫我們做了計算size和調用resize 這2步。非常方便。代碼如下:

使用fit 還是會出現拉伸扭曲的情況,因此最好配合前面的centerCrop使用,代碼如下:

看一下對比圖:
fit(會拉伸):

          image_fit.png

fit & centerCrop (不會拉伸):

          fit_centerCrop.png

註意:特別註意,
1,fit 只對ImageView 有效
2,使用fit時,ImageView 寬和高不能為wrap_content,很好理解,因為它要測量寬高。

4. 圖片旋轉Rotation()

在圖片顯示到ImageView 之前,還可以對圖片做一些旋轉操作,調用rotate(int degree)方法

這個方法它是以(0,0)點旋轉,但是有些時候我們並不想以(0,0)點旋轉,還提供了另外一個方法可以指定原點:

  • rotate(float degrees, float pivotX, float pivotY) 以(pivotX, pivotY)為原點旋轉

5. 轉換器Transformation

Transformation 這就是Picasso的一個非常強大的功能了,它允許你在load圖片 -> into ImageView 中間這個過成對圖片做一系列的變換。比如你要做圖片高斯模糊、添加圓角、做度灰處理、圓形圖片等等都可以通過Transformation來完成。

來看一個高斯模糊的例子:

第一步, 首先定義一個轉換器繼承Transformation

  public static class BlurTransformation implements Transformation{

        RenderScript rs;

        public BlurTransformation(Context context) {
            super();
            rs = RenderScript.create(context);
        }

        @Override
        public Bitmap transform(Bitmap bitmap) {
            // Create another bitmap that will hold the results of the filter.
            Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            // Allocate memory for Renderscript to work with
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
            Allocation output = Allocation.createTyped(rs, input.getType());

            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setInput(input);

            // Set the blur radius
            script.setRadius(25);

            // Start the ScriptIntrinisicBlur
            script.forEach(output);

            // Copy the output to the blurred bitmap
            output.copyTo(blurredBitmap);

            bitmap.recycle();

            return blurredBitmap;
        }

        @Override
        public String key() {
            return "blur";
        }
    }

第二步, 載入圖片的時候,在into 方法前面調用 transform方法 應用Transformation

  Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .transform(new BlurTransformation(this))
                .into(mBlurImage);

看一下效果圖:

        transformation.png

上面為原圖,下麵為高斯模糊圖

是不是很強大,任何複雜的變換都可以通過Transformation 來做。

還不止於此,還有更強大的功能。可以在一個請求上應用多個Transformation

比如:我想先做個度灰處理然後在做一個高斯模糊圖:

第一步, 定義一個度灰的Transformation

  public static class GrayTransformation implements Transformation{

        @Override
        public Bitmap transform(Bitmap source) {
            int width, height;
            height = source.getHeight();
            width = source.getWidth();

            Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            Canvas c = new Canvas(bmpGrayscale);
            Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
            paint.setColorFilter(f);
            c.drawBitmap(source, 0, 0, paint);

            if(source!=null && source!=bmpGrayscale){
                source.recycle();
            }
            return bmpGrayscale;
        }

        @Override
        public String key() {
            return "gray";
        }
    }

第二步, 如果是多個Transformation操作,有兩種方式應用
方式一:直接調用多次transform 方法,不會覆蓋的。它只是保存到了一個List 裡面

  Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .fit()
                .centerCrop()
                .transform(new GrayTransformation())//度灰處理
                .transform(new BlurTransformation(this))//高斯模糊
                .into(mBlurImage);

需要註意調用的順序
方式二:接受一個List,將Transformation 放大list 里

     List<Transformation> transformations = new ArrayList<>();
        transformations.add(new GrayTransformation());
        transformations.add(new BlurTransformation(this));

        Picasso.with(this).load(URL)
                .placeholder(R.drawable.default_bg)
                .error(R.drawable.error_iamge)
                .fit()
                .centerCrop()
                .transform(transformations)
                .into(mBlurImage);

效果圖:

          gray_blur.png

如上圖,第一張為度灰操作,第二張為 度灰+高斯模糊

另外發現了一個開源庫,專門寫了很多好玩的Transformation,有興趣的可以看一下:
picasso-transformations

6. 請求優先順序

Picasso 為請求設置有優先順序,有三種優先順序,LOW、NORMAL、HIGH。預設情況下都是NORMAL,除了調用fetch 方法,fetch 方法的優先順序是LOW。

可以通過priority方法設置請求的優先順序,這會影響請求的執行順序,但是這是不能保證的,它只會往高的優先順序靠攏。代碼如下:

7. Tag管理請求

Picasso 允許我們為一個請求設置tag來管理請求,看一下對應的幾個方法:
下麵3個方法是Picasso這個類的:

  • cancelTag(Object tag) 取消設置了給定tag的所有請求
  • pauseTag(Object tag) 暫停設置了給定tag 的所有請求
  • resumeTag(Object tag) resume 被暫停的給定tag的所有請求

還有一個方法是RequestCreator的:

  • tag(Object tag) 為請求設置tag

幾個方法的意思也很明確,就是我們可以暫停、resume、和取消請求,可以用在哪些場景呢?

場景一: 比如一個照片流列表,當我們快速滑動列表瀏覽照片的時候,後臺會一直發起請求載入照片的,這可能會導致卡頓,那麼我們就可以為每個請求設置一個相同的Tag,在快速滑動的時候,調用pauseTag暫停請求,當滑動停止的時候,調用resumeTag恢復請求,這樣的體驗是不是就會更好一些呢。

Adapter中添加如下代碼:

Activity中為RecyclerView添加滑動監聽:

場景二: 比如一個照片流列表界面,在弱網環境下,載入很慢,退出這個界面時可能會有很多請求沒有完成,這個時候我們就可 以通過tag 來取消請求了。

8. 同步/非同步載入圖片

Picasso 載入圖片也有同步/非同步兩種方式
同步get() 
很簡單,同步載入使用get() 方法,返回一個Bitmap 對象,代碼如下:

註意:使用同步方式載入,不能放在主線程來做。

非同步fetch()
一般直接載入圖片通過into顯示到ImageView 是非同步的方式,除此之外,還提供了2個非同步的方法:

  • fetch() 非同步方式載入圖片
  • fetch(Callback callback) 非同步方式載入圖片並給一個回調介面。

這裡就要吐槽一下介面設計了,回調並沒有返回Bitmap, 不知道作者是怎麼考慮的,只是一個通知效果,知道請求失敗還是成功。
**fetch 方法非同步載入圖片並沒有返回Bitmap,這個方法在請求成功之後,將結果存到了緩存,包括磁碟和記憶體緩存。所以使用這種方式載入圖片適用於這種場景:知道稍後會載入圖片,使用fetch 先載入緩存,起到一個預載入的效果。 **

9. 緩存(Disk 和 Memory)

Picasso 有記憶體緩存(Memory)和磁碟緩存( Disk), 首先來看一下源碼中對於緩存的介紹:

  • LRU memory cache of 15% the available application RAM
  • Disk cache of 2% storage space up to 50MB but no less than 5MB. (Note: this is only
    available on API 14+ <em>or</em> if you are using a standalone library that provides a disk cache on all API levels like OkHttp)
  • Three download threads for disk and network access.

可以看出,記憶體緩存是使用的LRU 策略的緩存實現,它的大小是記憶體大小的15%,可以自定義它的大小,最後在擴展那一章節再講,磁碟緩存是磁碟容量的2%但是不超過50M,不少於5M。處理一個請求的時候,按照這個順訊檢查:memory->disk->network 。先檢查有木有記憶體緩存,如果命中,直接返回結果,否則檢查磁碟緩存,命中則返回結果,沒有命中則從網上獲取。

預設情況下,Picasso 記憶體緩存和磁碟緩存都開啟了的,也就是載入圖片的時候,記憶體和磁碟都緩存了,但是有些時候,我們並不需要緩存,比如說:載入一張大圖片的時候,如果再記憶體中保存一份,很容易造成OOM,這時候我們只希望有磁碟緩存,而不希望緩存到記憶體,因此就需要我們設置緩存策略了。Picasso 提供了這樣的方法。

方式一:memoryPolicy 設置記憶體緩存策略
就像上面所說的,有時候我們不希望有記憶體緩存,我們可以通過 memoryPolicy 來設置。MemoryPolicy是一個枚舉,有兩個值

NO_CACHE:表示處理請求的時候跳過檢查記憶體緩存
**NO_STORE: ** 表示請求成功之後,不將最終的結果存到記憶體。

示例代碼如下:

方式二:networkPolicy 設置磁碟緩存策略

和記憶體緩存一樣,載入一張圖片的時候,你也可以跳過磁碟緩存,和記憶體緩存策略的控制方式一樣,磁碟緩存調用方法networkPolicy(NetworkPolicy policy, NetworkPolicy... additional) , NetworkPolicy是一個枚舉類型,有三個值:

NO_CACHE: 表示處理請求的時候跳過處理磁碟緩存
NO_STORE:表示請求成功後,不將結果緩存到Disk,但是這個只對OkHttp有效。
OFFLINE: 這個就跟 上面兩個不一樣了,如果networkPolicy方法用的是這個參數,那麼Picasso會強制這次請求從緩存中獲取結果,不會發起網路請求,不管緩存中能否獲取到結果。

使用示例:

強制從緩存獲取:

10. Debug 和日誌

緩存指示器

上一節說了,Picasso 有記憶體緩存和磁碟緩存,先從記憶體獲取,沒有再去磁碟緩存獲取,都有就從網路載入,網路載入是比較昂貴和耗時的。因此,作為一個開發者,我們往往需要載入的圖片是從哪兒來的(記憶體、Disk還是網路),Picasso讓我們很容易就實現了。只需要調用一個方法setIndicatorsEnabled(boolean)就可以了,它會在圖片的左上角出現一個帶色塊的三角形標示,有3種顏色,綠色表示從記憶體載入、藍色表示從磁碟載入、紅色表示從網路載入。

效果圖:

              cache_indicator.png

如上圖所示,第一張圖從網路獲取,第二張從磁碟獲取,第三張圖從記憶體獲取。

看一下源碼中定義指示器的顏色:

可以很清楚看出,對應三種顏色代表著圖片的來源。

日誌
上面的指示器能夠很好的幫助我們看出圖片的來源,但是有時候我們需要更詳細的信息,Picasso,可以列印一些日誌,比如一些關鍵方法的執行時間等等,我們只需要調用setLoggingEnabled(true)方法,然後App在載入圖片的過程中,我們就可以從logcat 看到一些關鍵的日誌信息。

11. Picasso 擴展

到目前為止,Picasso的基本使用已經講得差不多了,但是在實際項目中我們這可能還滿足不了我們的需求,我們需要對它做一些自己的擴展,比如我們需要換緩存的位置、我們需要擴大緩存、自定義線程池、自定義下載器等等。這些都是可以的,接下來我們來看一下可以做哪些方面的擴展。

用Builder 自己構造一個Picasso Instance
我們來回顧一下前面是怎麼用Picasso 載入圖片的:

總共3步:
(1) 用with方法獲取一個Picasso 示例
(2) 用load方法載入圖片
(3) 用into 放法顯示圖片

首先Picasso是一個單例模式,我們每一次獲取的示例都是預設提供給我們的實例。但是也可以不用它給的Instance,我們直接用builder來構造一個Picasso:

這樣我們就構造了一個局部的Picasso實例,當然了,我們直接用new 了一個builder,然後build()生成了一個Picasso。這跟預設的通過with方法獲取的實例是一樣的。那麼現在我們就可以配置一些自定義的功能了。

配置自定義下載器 downLoader
如果我們不想用預設提供的Downloader,那麼我們可以自定義一個下載器然後配置進去。舉個例子:

總共5步:
(1) 先自定義一個Downloader(只是舉個例子,並沒有實現):

(2) 然後通過builder 配置:

這樣配置後,我們用build()生成的Picasso 實例來載入圖片就會使用自定義的下載器來下載圖片了。

(3) 配置緩存
前面說過,記憶體緩存是用的LRU Cahce ,大小是手機記憶體的15% ,如果你想緩存大小更大一點或者更小一點,可以自定義,然後配置。

上面只是一個簡單的舉例,當然了你可以自定義,也可以使用LRUCache,改變大小,改變存儲路徑等等。

提示: 很遺憾,好像沒有提供改變磁碟緩存的介面,那就只能用預設的了。

(4) 配置線程池
Picasso 預設的線程池的核心線程數為3,如果你覺得不夠用的話,可以配置自己需要的線程池,舉個列子:

(5) 配置全局的 Picasso Instance
上面說的這些自定義配置項目都是應用在一個局部的Picasso instance 上的,我們不可能每一次使用都要重新配置一下,這樣就太麻煩了。我們希望我們的這些自定義配置能在整個項目都應用上,並且只配置一次。其實Picasso 給我們提供了這樣的方法。可以調用setSingletonInstance(Picasso picasso)就可以了,看一下這個方法的源碼:

設置一個通過with方法返回的全局instance。我們只希望配置一次,所以,我們應該在Application 的onCreate方法中做全局配置就可以了。app一啟動就配置好,然後直接和前面的使用方法一樣,調用with方法獲取Picasso instance 載入圖片就OK了。

因此在Application 中添加如下代碼:

然後應用這些自定義配置載入圖片

用法和以前的一樣,但是我們已經將我們的自定義配置應用上了。

結尾

以上就是對Picasso 用法的全部總結,如有什麼問題,歡迎留言指正。Picasso真的是一個強大的圖片載入緩存庫,API 簡單好用,而且是鏈式調用的(這點我特別喜歡)。官方文檔寫的比較簡單,很多用法都要看源碼和註釋才知道。希望本文能給才開始使用Picasso 的同學一點幫助。



作者:依然範特稀西
鏈接:https://www.jianshu.com/p/c68a3b9ca07a
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 思路: 先將取出的值隨機排序,然後在隨機排序的每次取第一條的結果 舉例如下: select * from(select t.code fromTBIZOPS_PROVINCE t ORDER BY DBMS_RANDOM.RANDOM())where rownum < 2;select * from ...
  • 吃雞游戲火了之後,身邊朋友們都在說“大吉大利,今晚吃雞”、“今天你吃雞了嗎?”作為游戲愛好者的達妹本也想加入吃雞大隊,但無奈不瞭解游戲,還手殘! 當然達妹並不認輸,在網上積極搜索攻略,然後達妹就發現!有很多會大數據的技術人員們,用大數據來分析吃雞的數據,得到一份最強吃雞攻略! 下麵就來看看怎麼利用大 ...
  • 隨著國家大數據戰略的實施和人工智慧、雲服務、物聯網等產業的高速發展,大數據成為了2018年最為熱門的職業之一,也成為了人們茶前飯後討論的熱點!經過2018年大數據一個爆炸式的發展,隨後幾年大數據學習潮流已成必然,“超高薪、高大上、前景光明”成為大數據行業的代名詞。 雖然大數據是一個炙手可熱的行業,但 ...
  • 官網網址參考: https://docs.oracle.com/cd/B19306_01/appdev.102/b14258/d_stats.htm#CIHBIEII https://docs.oracle.com/cd/B12037_01/server.101/b10759/statements_ ...
  • Preface I've installed MasterHA yesterday,Now let's test the master-slave switch and failover feature. Framework Hostname IP Port Identity OS Version ...
  • 前言 學習Android相關知識,數據存儲是其中的重點之一,如果不瞭解數據,那麼讓你跟一款沒有數據的應用玩,你能玩多久呢?答案是這和沒有手機幾乎是差不多的。我們聊QQ,聊微信,看新聞,刷朋友圈等都是看裡面的數據,所以在Android中數據對我們是多麼重要。 數據,如今是數據大時代,誰擁有數據,誰就能 ...
  • 一、EditText介紹 ①EditText是一個輸入框,在Android開發中是常用的控制項。也是獲取用戶數據的一種方式。 ②EditText是TextView的子類,它繼承了TextView的所有屬性。 二、常用屬性 1 輸入類型:android:inputType="value" value列表 ...
  • 在做android圖片載入的時候,由於手機屏幕受限,很多大圖載入過來的時候,我們要求等比例縮放,比如按照固定的寬度,等比例縮放高度,使得圖片的尺寸比例得到相應的縮放,但圖片沒有變形。顯然按照android:scaleType不能實現,因為會有很多限制,所以必須要自己寫演算法。 通過Picasso來縮放 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...