Pasmowanie kolorów i artefakty z gradientami pomimo stosowania RGBA_8888 wszędzie

Zdaję sobie sprawę z tego, że pasmowanie kolorów to stary kasztan problemu, który był wielokrotnie dyskutowany z różnymi dostarczonymi rozwiązaniami (które zasadniczo sprowadzają się do używania 32-bitowego całego lub używać ditheringu). W rzeczywistości nie tak dawno temuzapytał, a następnie odpowiedział na moje własne pytanie SO odnośnie tego. Wtedy myślałem, że rozwiązanie, które umieściłem w odpowiedzi na to pytanie (które ma zastosowaniesetFormat(PixelFormat.RGBA_8888) doWindow a także doHolder w przypadku aSurfaceView) rozwiązał problem w mojej aplikacji na dobre. Przynajmniej rozwiązanie sprawiło, że gradient wyglądał bardzo ładnie na urządzeniach, na których pracowałem wtedy (najprawdopodobniej na Androida 2.2).

Obecnie pracuję nad HTC One X (Android 4.0) i Asus Nexus 7 (Android 4.1). Próbowałem zastosować szary gradient do całego obszaru aSurfaceView. Nawet jeśli zapewniłam, że zawierająceWindow iHolder są skonfigurowane dla koloru 32-bitowego, otrzymuję okropne artefakty pasmowe. W rzeczywistości na Nexusie 7Widzę nawet, jak artefakty się poruszają. Dzieje się tak nie tylko naSurfaceView który jest oczywiście ciągły, ale także normalnyView Dodałem obok, aby narysować dokładnie ten sam gradient do celów testowych, który narysowałby raz. Sposób, w jaki te artefakty są i wydają się poruszać, wygląda oczywiście okropnie i tak jestwłaściwie jak oglądanie telewizji analogowej ze słabym sygnałem. ObojeView iSurfaceView wykazują dokładnie te same artefakty, które poruszają się razem.

Moim zamiarem jest używanie 32-bitowego w całym tekście i nie używać ditheringu. Mam wrażenie, żeWindow był 32-bitowy domyślnie na długo przed Androidem 4.0. Poprzez zastosowanieRGBA_8888 wSurfaceView Spodziewałbym się, że wszystko będzie 32-bitowe w całym tekście, unikając w ten sposób jakichkolwiek artefaktów.

Zwracam uwagę, że istnieją inne pytania dotyczące SO, w których ludzie zauważyli, żeRGBA_8888 nie działa już na platformach 4.0 / 4.1.

To jest zrzut ekranu z mojego Nexusa 7, z normalnymView na górze i aSurfaceView poniżej, oba stosują ten sam gradient doCanvas. Oczywiście, nie pokazuje artefaktów tak dobrze, jak podczas oglądania ekranu, więc wyświetlanie tego ekranu jest prawdopodobnie bezcelowe. Chcę jednak podkreślić, że pasmo naprawdę wygląda okropnie na ekranie Nexusa.Edytować: W rzeczywistości zrzut ekranu naprawdę nie pokazuje artefaktóww ogóle. Artefakty, które widzę w Nexusie 7, nie są jednolite; z natury wygląda losowo.

TestActivity użyte do utworzenia powyższego:

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.os.Bundle;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.widget.LinearLayout;

public class GradientTest extends Activity {

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        getWindow().setFormat(PixelFormat.RGBA_8888);
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);      
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
        lp.copyFrom(getWindow().getAttributes());
        lp.format = PixelFormat.RGBA_8888;
        getWindow().setAttributes(lp);     
        LinearLayout ll = new LinearLayout(this);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500,500);
        params.setMargins(20, 0, 0, 0);
        ll.addView(new GradientView(this), params);    
        ll.addView(new GradientSurfaceView(this), params);
        ll.setOrientation(LinearLayout.VERTICAL);
        setContentView(ll);
    }


    public class GradientView extends View {

        public GradientView(Context context) {
            super(context);     
        }

        @Override
        protected void onDraw(Canvas canvas) {

            Paint paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setAntiAlias(false);
            paint.setFilterBitmap(false);
            paint.setDither(false); 
            Shader shader = new LinearGradient(
                    0,
                    0,
                    0,
                    500,
                    //new int[]{0xffafafaf, 0xff414141},
                    new int[]{0xff333333, 0xff555555},
                    null,

                    Shader.TileMode.CLAMP
                    );

            paint.setShader(shader);    
            canvas.drawRect(0,0,500,500, paint);
        }       
    }




    public class GradientSurfaceView extends SurfaceView implements Callback {

        public GradientSurfaceView(Context context) {
            super(context);

            getHolder().setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients 
            SurfaceHolder holder = getHolder();
            holder.addCallback(this);    
        }


        Paint paint;
        private GraphThread thread;

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            holder.setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients    

            paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setAntiAlias(false);
            paint.setFilterBitmap(false);
            paint.setDither(false); 

            Shader shader = new LinearGradient(
                    0,
                    0,
                    0,
                    500,
                    //new int[]{0xffafafaf, 0xff414141},
                    new int[]{0xff333333, 0xff555555},
                    null,
                    Shader.TileMode.CLAMP
                    );


            paint.setShader(shader);  



            thread = new GraphThread(holder, new Handler() );
            thread.setName("GradientSurfaceView_thread");
            thread.start();
        }

        class GraphThread extends Thread {

            /** Handle to the surface manager object we interact with */
            private SurfaceHolder mSurfaceHolder;   

            public GraphThread(SurfaceHolder holder, Handler handler) {
                mSurfaceHolder = holder;
                holder.setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients  
            }

            @Override
            public void run() {

                Canvas c = null;

                while (true) {

                    try {
                        c = mSurfaceHolder.lockCanvas();

                        synchronized (mSurfaceHolder) {

                            if (c != null){


                                c.drawRect(0,0,500,500, paint);

                            }
                        }                                 
                    } 

                    finally {
                        if (c != null) {
                            mSurfaceHolder.unlockCanvasAndPost(c);
                        }
                    }
                }
            }    

        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }
    }


}

Zainstalowałem aplikację o nazwie Display Tester z Google Play. Ta aplikacja może być używana do tworzenia gradientów testowych na ekranie. Chociaż jej gradienty nie wyglądają idealnie, wydają się nieco lepsze niż to, co udało mi się osiągnąć, co sprawia, że ​​zastanawiam się, czy jest jeszcze jeden środek, który mogę zrobić, aby zapobiec powstawaniu pasów.

Inną rzeczą, którą zauważam, jest to, że aplikacja Display Tester informuje, że ekran mojego Nexusa jest 32-bitowy.

Aby uzyskać informacje, wyraźnie włączam akcelerację sprzętową. Moje poziomy SDK to:

 <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15"></uses-sdk>

Inną rzeczą, którą zauważam, jest domyślne tło gradientowe dlaActivity, które, jak rozumiem, jest cechą Holo, jest również bardzo ograniczone. Nie widać tego na zrzucie ekranu. I właśnie zauważyłem, że pasmo tła porusza się na krótko w moim Nexusie 7, współczując ruchowi bandowania w moich dwóchViews. Jeśli utworzę całkowicie nowy projekt Androida z domyślnym „pustym”Activity, theActivity pokazuje paskudne pasmowe tło gradientowe zarówno na moim Nexusie, jak i HTC One X. Czy to normalne? Rozumiem, że domyślne tło czarnego / fioletowego gradientu jest tym, czym jestActivity powinien mieć włączoną akcelerację sprzętową. Cóż, bez względu na to, czy akceleracja sprzętowa jest włączona, czy nie, widzę to samo paskowane paskowanieActivity gradient tła. Dzieje się tak nawet w moim pustym projekcie testowym, którego docelowym zestawem SDK jest 15. Aby wyjaśnić, sposób włączania lub wyłączania akceleracji sprzętowej jest jawnie używanyandroid:hardwareAccelerated="true" iandroid:hardwareAccelerated="false".

Nie jestem pewien, czy moja obserwacja na temat Holo czarny / fioletowyActivity tło gradientowe ma coś wspólnego z moim podstawowym pytaniem, ale wydaje się dziwnie powiązane. Dziwne jest również to, że wygląda na tak niską jakość (tzn. Pasmową) i wygląda tak samo niezależnie od tego, czy jest włączona akceleracja sprzętowa. Zatem drugie pytanie brzmi: Kiedy maszActivity z domyślnym tłem gradientu Holo, a dla każdego przypadku akceleracji sprzętowej, która jest włączona, a następnie wyłączona, czy to tło gradientowe (a) powinno być obecne i (b) wyglądać idealnie gładko? Zadałbym to w osobnym pytaniu, ale znowu wydaje się to powiązane.

Podsumowując: Podstawowym problemem, jaki mam, jest zastosowanie tła gradientowego doSurfaceView wydaje się, że po prostu nie można tego zrobić na moim Nexusie 7. Problemem jest nie tylko pasowanie (co mogłem z radością pogodzić, gdyby tak było); Faktem jest, że pasmo ma losowy charakter przy każdym losowaniu. Oznacza to, że aSurfaceView który stale przerysowuje kończy się posiadaniem ruchomego, rozmytego tła.

questionAnswers(4)

yourAnswerToTheQuestion