Szukaj…


Tworzenie własnych widoków

Jeśli potrzebujesz całkowicie spersonalizowanego widoku, musisz podklasę View (nadklasa wszystkich widoków Androida) i podać niestandardowe onMeasure(...) rozmiaru ( onMeasure(...) ) i rysowania ( onDraw(...) ):

  1. Utwórz szkielet widoku niestandardowego: jest on zasadniczo taki sam dla każdego widoku niestandardowego. Tutaj tworzymy szkielet niestandardowego widoku, który może narysować buźkę o nazwie SmileyView :

    public class SmileyView extends View {
        private Paint mCirclePaint;
        private Paint mEyeAndMouthPaint;
    
        private float mCenterX;
        private float mCenterY;
        private float mRadius;
        private RectF mArcBounds = new RectF();
    
        public SmileyView(Context context) {
            this(context, null, 0);
        }
    
        public SmileyView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SmileyView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initPaints();
        }
    
        private void initPaints() {/* ... */}
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {/* ... */}
    
        @Override
        protected void onDraw(Canvas canvas) {/* ... */}
    }
    
  2. Zainicjuj swoje farby: obiekty Paint to pędzle wirtualnego płótna określające sposób renderowania obiektów geometrycznych (np. Kolor, styl wypełnienia i obrysu itp.). Tutaj tworzymy dwie Paint , jedną żółtą wypełnioną farbę dla koła i jedną czarną farbę obrysową dla oczu i ust:

    private void initPaints() {
        mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mCirclePaint.setStyle(Paint.Style.FILL);
        mCirclePaint.setColor(Color.YELLOW);
        mEyeAndMouthPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mEyeAndMouthPaint.setStyle(Paint.Style.STROKE);
        mEyeAndMouthPaint.setStrokeWidth(16 * getResources().getDisplayMetrics().density);
        mEyeAndMouthPaint.setStrokeCap(Paint.Cap.ROUND);
        mEyeAndMouthPaint.setColor(Color.BLACK);
    }
    
  3. Zaimplementuj własną onMeasure(...) : jest to wymagane, aby układy nadrzędne (np. FrameLayout ) mogły poprawnie wyrównać widok niestandardowy. Zapewnia zestaw measureSpecs , których można użyć do określenia wysokości i szerokości widoku. Tutaj tworzymy kwadrat, upewniając się, że wysokość i szerokość są takie same:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int w = MeasureSpec.getSize(widthMeasureSpec);
        int h = MeasureSpec.getSize(heightMeasureSpec);
    
        int size = Math.min(w, h);
        setMeasuredDimension(size, size);
    }
    

    Pamiętaj, że onMeasure(...) musi zawierać co najmniej jedno wywołanie setMeasuredDimension(..) przeciwnym razie widok niestandardowy ulegnie awarii z powodu IllegalStateException .

  4. Zaimplementuj własną onSizeChanged(...) : pozwala to uchwycić bieżącą wysokość i szerokość niestandardowego widoku, aby odpowiednio dostosować kod renderowania. Tutaj po prostu obliczamy nasze centrum i nasz promień:

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        mCenterX = w / 2f;
        mCenterY = h / 2f;
        mRadius = Math.min(w, h) / 2f;
    }
    
  5. Zaimplementuj własną onDraw(...) : w tym miejscu onDraw(...) rzeczywiste renderowanie widoku. Zapewnia obiekt Canvas , na którym można rysować (zobacz oficjalną dokumentację Canvas dla wszystkich dostępnych metod rysowania).

    @Override
    protected void onDraw(Canvas canvas) {
        // draw face
        canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint);
        // draw eyes
        float eyeRadius = mRadius / 5f;
        float eyeOffsetX = mRadius / 3f;
        float eyeOffsetY = mRadius / 3f;
        canvas.drawCircle(mCenterX - eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius, mEyeAndMouthPaint);
        canvas.drawCircle(mCenterX + eyeOffsetX, mCenterY - eyeOffsetY, eyeRadius, mEyeAndMouthPaint);
        // draw mouth
        float mouthInset = mRadius /3f;
        mArcBounds.set(mouthInset, mouthInset, mRadius * 2 - mouthInset, mRadius * 2 - mouthInset);
        canvas.drawArc(mArcBounds, 45f, 90f, false, mEyeAndMouthPaint);
    }
    
  6. Dodaj widok niestandardowy do układu: widok niestandardowy można teraz dołączać do wszystkich plików układu, które posiadasz. Tutaj po prostu FrameLayout go w FrameLayout :

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <com.example.app.SmileyView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
    

Pamiętaj, że zaleca się zbudowanie projektu po zakończeniu kodu widoku. Bez jego zbudowania nie będzie można zobaczyć widoku na ekranie podglądu w Android Studio.

Po złożeniu wszystkiego powinieneś powitać następujący ekran po uruchomieniu działania zawierającego powyższy układ:

SmileyView używane w aktywności

Dodawanie atrybutów do widoków

Widoki niestandardowe mogą również przyjmować atrybuty niestandardowe, których można używać w plikach zasobów układu Androida. Aby dodać atrybuty do widoku niestandardowego, wykonaj następujące czynności:

  1. Zdefiniuj nazwę i typ swoich atrybutów: odbywa się to w res/values/attrs.xml (utwórz go, jeśli to konieczne). Poniższy plik definiuje atrybut koloru dla koloru twarzy naszej buźki i atrybut wyliczania dla wyrażenia buźki:

    <resources>
        <declare-styleable name="SmileyView">
            <attr name="smileyColor" format="color" />
            <attr name="smileyExpression" format="enum">
                <enum name="happy" value="0"/>
                <enum name="sad" value="1"/>
            </attr>
        </declare-styleable>
        <!-- attributes for other views -->
    </resources>
    
  2. Użyj swoich atrybutów w układzie: można to zrobić w dowolnych plikach układu, które używają widoku niestandardowego. Poniższy plik układu tworzy ekran ze szczęśliwą żółtą buźką:

    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_height="match_parent"
        android:layout_width="match_parent">
        
        <com.example.app.SmileyView
            android:layout_height="56dp"
            android:layout_width="56dp"
            app:smileyColor="#ffff00"
            app:smileyExpression="happy" />
    </FrameLayout>
    

    Wskazówka: Niestandardowe atrybuty nie działają z tools: przedrostek w Android Studio 2.1 i starszych (i ewentualnie w przyszłych wersjach). W tym przykładzie zastąpienie app:smileyColor tools:smileyColor spowodowałoby, że smileyColor nie byłby ustawiany w czasie wykonywania ani w czasie projektowania.

  3. Przeczytaj swoje atrybuty: odbywa się to w kodzie źródłowym widoku niestandardowego. Poniższy fragment SmileyView pokazuje, w jaki sposób można wyodrębnić atrybuty:

    public class SmileyView extends View {
        // ...
    
        public SmileyView(Context context) {
            this(context, null);
        }
    
        public SmileyView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public SmileyView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SmileyView, defStyleAttr, 0);
            mFaceColor = a.getColor(R.styleable.SmileyView_smileyColor, Color.TRANSPARENT);
            mFaceExpression = a.getInteger(R.styleable.SmileyView_smileyExpression, Expression.HAPPY);
            // Important: always recycle the TypedArray
            a.recycle();
    
            // initPaints(); ...
        }
    }
    
  4. (Opcjonalnie) Dodaj styl domyślny: można to zrobić, dodając styl z wartościami domyślnymi i ładując go w widoku niestandardowym. Poniższy domyślny styl buźki przedstawia szczęśliwy żółty:

    <!-- styles.xml -->
    <style name="DefaultSmileyStyle">
        <item name="smileyColor">#ffff00</item>
        <item name="smileyExpression">happy</item>
    </style>
    

    Który jest stosowany w naszym SmileyView , dodając go jako ostatni parametr wywołania obtainStyledAttributes (patrz kod w kroku 3):

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SmileyView, defStyleAttr, R.style.DefaultSmileyViewStyle);
    

    Zauważ, że wszelkie wartości atrybutów ustawione w napompowanym pliku układu (patrz kod w kroku 2) zastąpią odpowiednie wartości stylu domyślnego.

  5. (Opcjonalnie) Zapewnij style w motywach: dzieje się to poprzez dodanie nowego atrybutu odwołania do stylu, który może być używany w motywach i zapewnienie stylu dla tego atrybutu. Tutaj po prostu nazywamy nasz atrybut referencyjny smileyStyle :

    <!-- attrs.xml -->
    <attr name="smileyStyle" format="reference" />
    

    Dla którego następnie zapewniamy styl w naszym motywie aplikacji (tutaj ponownie wykorzystujemy domyślny styl z kroku 4):

    <!-- themes.xml -->
    <style name="AppTheme" parent="AppBaseTheme">
        <item name="smileyStyle">@style/DefaultSmileyStyle</item>
    </style>
    

Tworzenie widoku złożonego

Widok złożony to niestandardowa ViewGroup która jest traktowana jako pojedynczy widok przez otaczający kod programu. Taki ViewGroup może być naprawdę przydatny w projektach podobnych do DDD , ponieważ może odpowiadać agregacji, w tym przykładzie Kontaktowi. Można go ponownie wykorzystać wszędzie tam, gdzie wyświetlany jest kontakt.

Oznacza to, że otaczający kod kontrolera, działanie, fragment lub adapter, może po prostu przekazać obiekt danych do widoku bez dzielenia go na kilka różnych widżetów interfejsu użytkownika.

Ułatwia to ponowne użycie kodu i zapewnia lepszy projekt zgodnie z założeniami SOLID .

Układ XML

To jest zwykle miejsce, w którym zaczynasz. Masz istniejący fragment XML, którego używasz ponownie, być może jako <include/> . Wyodrębnij go do osobnego pliku XML i zawiń znacznik root w elemencie <merge> :

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

        <ImageView
            android:id="@+id/photo"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_alignParentRight="true" />

        <TextView
            android:id="@+id/name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_toLeftOf="@id/photo" />

        <TextView
            android:id="@+id/phone_number"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/name"
            android:layout_toLeftOf="@id/photo" />
</merge>

Ten plik XML działa doskonale w Edytorze układu w Android Studio. Możesz traktować go jak każdy inny układ.

Złożony ViewGroup

Po utworzeniu pliku XML utwórz niestandardową grupę widoków.

import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.ImageView;
import android.widget.TextView;

import myapp.R;

/**
 * A compound view to show contacts.
 *
 * This class can be put into an XML layout or instantiated programmatically, it
 * will work correctly either way.
 */
public class ContactView extends RelativeLayout {

    // This class extends RelativeLayout because that comes with an automatic
    // (MATCH_PARENT, MATCH_PARENT) layout for its child item. You can extend
    // the raw android.view.ViewGroup class if you want more control. See the
    // note in the layout XML why you wouldn't want to extend a complex view
    // such as RelativeLayout.

    // 1. Implement superclass constructors.
    public ContactView(Context context) {
        super(context);
        init(context, null);
    }

    // two extra constructors left out to keep the example shorter

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public ContactView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    // 2. Initialize the view by inflating an XML using `this` as parent
    private TextView mName;
    private TextView mPhoneNumber;
    private ImageView mPhoto;

    private void init(Context context, AttributeSet attrs) {
        LayoutInflater.from(context).inflate(R.layout.contact_view, this, true);
        mName = (TextView) findViewById(R.id.name);
        mPhoneNumber = (TextView) findViewById(R.id.phone_number);
        mPhoto = (ImageView) findViewById(R.id.photo);
    }

    // 3. Define a setter that's expressed in your domain model. This is what the example is
    //    all about. All controller code can just invoke this setter instead of fiddling with
    //    lots of strings, visibility options, colors, animations, etc. If you don't use a
    //    custom view, this code will usually end up in a static helper method (bad) or copies 
    //    of this code will be copy-pasted all over the place (worse).
    public void setContact(Contact contact) {
        mName.setText(contact.getName());
        mPhoneNumber.setText(contact.getPhoneNumber());
        if (contact.hasPhoto()) {
            mPhoto.setVisibility(View.VISIBLE);
            mPhoto.setImageBitmap(contact.getPhoto());
        } else {
            mPhoto.setVisibility(View.GONE);
        }
    }
}

Metoda init(Context, AttributeSet) służy do odczytywania niestandardowych atrybutów XML, jak wyjaśniono w części Dodawanie atrybutów do widoków .

Dzięki tym elementom możesz używać ich w swojej aplikacji.

Wykorzystanie w XML

Oto przykład fragment_contact_info.xml ilustrujący sposób umieszczenia pojedynczego ContactView na liście wiadomości:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!-- The compound view becomes like any other view XML element -->
    <myapp.ContactView
        android:id="@+id/contact"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/message_list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

</LinearLayout>

Wykorzystanie w kodzie

Oto przykład RecyclerView.Adapter który pokazuje listę kontaktów. Ten przykład ilustruje, o ile czystszy jest kod kontrolera, gdy jest on całkowicie wolny od manipulacji widokiem.

package myapp;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;

public class ContactsAdapter extends RecyclerView.Adapter<ContactsViewHolder> {

    private final Context context;

    public ContactsAdapter(final Context context) {
        this.context = context;
    }

    @Override
    public ContactsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ContactView v = new ContactView(context); // <--- this
        return new ContactsViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ContactsViewHolder holder, int position) {
        Contact contact = this.getItem(position);
        holder.setContact(contact);  // <--- this
    }

    static class ContactsViewHolder extends RecyclerView.ViewHolder {

        public ContactsViewHolder(ContactView itemView) {
            super(itemView);
        }

        public void setContact(Contact contact) {
            ((ContactView) itemView).setContact(contact); // <--- this
        }
    }
}

Wskazówki dotyczące wydajności CustomView

Nie przydzielaj nowych obiektów w onDraw

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint = new Paint(); //Do not allocate here
}

Zamiast rysować rysunki na płótnie ...

drawable.setBounds(boundsRect);

drawable.draw(canvas);

Użyj mapy bitowej, aby przyspieszyć rysowanie:

canvas.drawBitmap(bitmap, srcRect, boundsRect, paint);

Nie przerysowuj całego widoku, aby zaktualizować tylko jego niewielką część. Zamiast tego narysuj konkretną część widoku.

invalidate(boundToBeRefreshed);

Jeśli twój widok wykonuje jakąś ciągłą animację, na przykład tarczę zegarka pokazującą każdą sekundę, przynajmniej zatrzymaj animację na onStop() działania i uruchom ją ponownie na onStart() działania.

Nie wykonuj żadnych obliczeń w metodzie widoku onDraw , powinieneś zamiast tego zakończyć rysowanie przed wywołaniem funkcji onDraw invalidate() . Korzystając z tej techniki, możesz uniknąć upuszczania ramki w swoim widoku.

Rotacje

Podstawowe operacje widoku to translacja, obracanie itp. Niemal każdy programista napotkał ten problem, gdy używa bitmapy lub gradientów w swoim widoku niestandardowym. Jeśli widok pokaże widok obrócony, a bitmapa musi zostać obrócona w tym widoku niestandardowym, wielu z nas pomyśli, że będzie on drogi. Wiele osób uważa, że obrócenie bitmapy jest bardzo kosztowne, ponieważ w tym celu należy przetłumaczyć jej matrycę pikseli. Ale prawda jest taka, że nie jest to takie trudne! Zamiast obracać mapę bitową, wystarczy obrócić samo płótno!

// Save the canvas state
int save = canvas.save();
// Rotate the canvas by providing the  center point as pivot and angle
canvas.rotate(pivotX, pivotY, angle);
// Draw whatever you want
// Basically whatever you draw here will be drawn as per the angle you rotated the canvas
canvas.drawBitmap(...);
// Now restore your your canvas to its original state
canvas.restore(save);
// Unless canvas is restored to its original state, further draw will also be rotated.

Widok złożony dla SVG / VectorDrawable jako drawableRight

Głównym motywem do opracowania tego złożonego widoku jest to, że poniżej wersji 5.0 urządzenia nie obsługują svg w trybie rysowania wewnątrz TextView / EditText. Jest jeszcze jedna plusy, możemy ustawić height i width od drawableRight wewnątrz EditText . Oddzieliłem go od mojego projektu i utworzyłem w osobnym module.

Nazwa modułu: custom_edit_drawable (krótka nazwa prefiksu- c_d_e)

Przedrostek „c_d_e_”, którego należy użyć, aby zasoby modułu aplikacji nie pomijały ich przez pomyłkę. Przykład: przedrostek „abc” jest używany przez google w bibliotece pomocy technicznej.

build.gradle

dependencies {
   compile 'com.android.support:appcompat-v7:25.3.1'
}

użyj AppCompat> = 23

Plik układu: c_e_d_compound_view.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <EditText
        android:id="@+id/edt_search"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text"
        android:maxLines="1"
        android:paddingEnd="40dp"
        android:paddingLeft="5dp"
        android:paddingRight="40dp"
        android:paddingStart="5dp" />

    <!--make sure you are not using ImageView instead of this-->
    <android.support.v7.widget.AppCompatImageView
        android:id="@+id/drawbleRight_search"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_gravity="right|center_vertical"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp" />
</FrameLayout>

Atrybuty niestandardowe: attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="EditTextWithDrawable">
        <attr name="c_e_d_drawableRightSVG" format="reference" />
        <attr name="c_e_d_hint" format="string" />
        <attr name="c_e_d_textSize" format="dimension" />
        <attr name="c_e_d_textColor" format="color" />
    </declare-styleable>
</resources>

Kod: EditTextWithDrawable.java

public class EditTextWithDrawable extends FrameLayout {
    public AppCompatImageView mDrawableRight;
    public EditText mEditText;

    public EditTextWithDrawable(Context context) {
        super(context);
        init(null);
    }

    public EditTextWithDrawable(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public EditTextWithDrawable(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public EditTextWithDrawable(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs);
    }

    private void init(AttributeSet attrs) {
        if (attrs != null && !isInEditMode()) {
            LayoutInflater inflater = (LayoutInflater) getContext()
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            inflater.inflate(R.layout.c_e_d_compound_view, this, true);
            mDrawableRight = (AppCompatImageView) ((FrameLayout) getChildAt(0)).getChildAt(1);
            mEditText = (EditText) ((FrameLayout) getChildAt(0)).getChildAt(0);

            TypedArray attributeArray = getContext().obtainStyledAttributes(
                    attrs,
                    R.styleable.EditTextWithDrawable);

            int drawableRes =
                    attributeArray.getResourceId(
                            R.styleable.EditTextWithDrawable_c_e_d_drawableRightSVG, -1);
            if (drawableRes != -1) {
                mDrawableRight.setImageResource(drawableRes);
            }

            mEditText.setHint(attributeArray.getString(
                    R.styleable.EditTextWithDrawable_c_e_d_hint));
            mEditText.setTextColor(attributeArray.getColor(
                    R.styleable.EditTextWithDrawable_c_e_d_textColor, Color.BLACK));
            int textSize = attributeArray.getDimensionPixelSize(R.styleable.EditTextWithDrawable_c_e_d_textSize, 15);
            mEditText.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
            android.view.ViewGroup.LayoutParams layoutParams = mDrawableRight.getLayoutParams();
            layoutParams.width = (textSize * 3) / 2;
            layoutParams.height = (textSize * 3) / 2;
            mDrawableRight.setLayoutParams(layoutParams);

            attributeArray.recycle();
        }
    }
}

Przykład: jak korzystać z powyższego widoku

Układ: Activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <com.customeditdrawable.AppEditTextWithDrawable
        android:id="@+id/edt_search_emp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:c_e_d_drawableRightSVG="@drawable/ic_svg_search"
        app:c_e_d_hint="@string/hint_search_here"
        app:c_e_d_textColor="@color/text_color_dark_on_light_bg"
        app:c_e_d_textSize="@dimen/text_size_small" />
</LinearLayout> 

Działanie: MainActivity.java

public class MainActivity extends AppCompatActivity {
    EditTextWithDrawable mEditTextWithDrawable;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mEditTextWithDrawable= (EditTextWithDrawable) findViewById(R.id.edt_search_emp);
    }
}

Reagowanie na zdarzenia dotykowe

Wiele niestandardowych widoków musi akceptować interakcję użytkownika w formie zdarzeń dotykowych. Dostęp do zdarzeń dotykowych można uzyskać, zastępując onTouchEvent . Istnieje wiele działań, które możesz odfiltrować. Głównymi są

  • ACTION_DOWN : ACTION_DOWN raz, gdy palec dotknie widoku po raz pierwszy.
  • ACTION_MOVE : Jest to wywoływane za każdym razem, gdy palec przesuwa się nieco w poprzek widoku. Dzwoni wiele razy.
  • ACTION_UP : jest to ostatnia czynność, która zostanie wywołana po oderwaniu palca od ekranu.

Możesz dodać następującą metodę do swojego widoku, a następnie obserwować dane wyjściowe dziennika po dotknięciu i przesunięciu palca po widoku.

@Override
public boolean onTouchEvent(MotionEvent event) {

    int x = (int) event.getX();
    int y = (int) event.getY();
    int action = event.getAction();

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            Log.i("CustomView", "onTouchEvent: ACTION_DOWN: x = " + x + ", y = " + y);
            break;

        case MotionEvent.ACTION_MOVE:
            Log.i("CustomView", "onTouchEvent: ACTION_MOVE: x = " + x + ", y = " + y);
            break;

        case MotionEvent.ACTION_UP:
            Log.i("CustomView", "onTouchEvent: ACTION_UP: x = " + x + ", y = " + y);
            break;
    }
    return true;
}

Dalsza lektura:



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow