Android เพิ่มภาพเคลื่อนไหวอย่างง่ายในขณะที่ setvisibility (view.Gone)


237

ฉันได้ออกแบบเลย์เอาต์ที่เรียบง่ายฉันได้เสร็จสิ้นการออกแบบโดยไม่มีแอนิเมชั่น แต่ตอนนี้ฉันต้องการเพิ่มแอนิเมชั่นเมื่อมีการคลิก textview event และฉันไม่รู้วิธีใช้ การออกแบบ xml ของฉันดูดีหรือไม่? ข้อเสนอแนะใด ๆ ที่จะได้รับการชื่นชม

XML ของฉัน

<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:longClickable="false"
    android:orientation="vertical"
    android:weightSum="16" >

<LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#00DDA0"
    android:layout_weight="3" >
</LinearLayout>
 <TextView
        android:id="@+id/Information1"
        android:layout_width="match_parent"
        android:layout_height="1dp" 
        android:text="Child Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>

 <LinearLayout
     android:id="@+id/layout1"
     android:layout_width="fill_parent"
     android:layout_height="0dp"
     android:layout_weight="8.5"
     android:background="#BBBBBB"
     android:orientation="vertical" >

     <TextView
         android:id="@+id/textView1"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
 </LinearLayout>

  <TextView
        android:id="@+id/Information2"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Parent Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
  <LinearLayout 
          android:id="@+id/layout2"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView2"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
   <TextView
        android:id="@+id/Information3"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Siblings" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
   <LinearLayout 
          android:id="@+id/layout3"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView3"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
    <TextView
        android:id="@+id/Information4"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Teacher Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
    <LinearLayout 
          android:id="@+id/layout4"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView4"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
     <TextView
        android:id="@+id/Information5"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Grade Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
     <LinearLayout 
          android:id="@+id/layout5"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
     <TextView
         android:id="@+id/textView5"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" />
      </LinearLayout>
      <TextView
        android:id="@+id/Information6"
        android:layout_width="match_parent"
        android:layout_height="0dp" 
        android:text="Health Information" 
        android:background="#0390BE"
        android:layout_weight="0.75"
        android:textColor="#FFFFFF"
        android:layout_gravity="center|fill_horizontal"/>
      <LinearLayout 
          android:id="@+id/layout6"
    android:layout_width="fill_parent"
    android:layout_height="0dp"
    android:orientation="vertical"
    android:background="#BBBBBB"
    android:layout_weight="8.5" >
    <TextView
         android:id="@+id/textView5"
         android:layout_width="match_parent"
         android:layout_height="match_parent"        
         android:text="TextView" 
         android:layout_weight="8.5" />
      </LinearLayout>

</LinearLayout>

จาวาของฉัน

public class Certify_Info extends Activity {

    private static TextView tv2,tv3,tv5,tv6,tv4,tv1;
    private static LinearLayout l1,l2,l3,l4,l5,l6;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_certify__info);

        tv1=(TextView) findViewById(R.id.Information1);
        tv2=(TextView) findViewById(R.id.Information2);
        tv3=(TextView) findViewById(R.id.Information3);
        tv4=(TextView) findViewById(R.id.Information4);
        tv5=(TextView) findViewById(R.id.Information5);
        tv6=(TextView) findViewById(R.id.Information6); 

        l1=(LinearLayout) findViewById(R.id.layout1);
        l2=(LinearLayout) findViewById(R.id.layout2);
        l3=(LinearLayout) findViewById(R.id.layout3);
        l4=(LinearLayout) findViewById(R.id.layout4);
        l5=(LinearLayout) findViewById(R.id.layout5);
        l6=(LinearLayout) findViewById(R.id.layout6); 

        l2.setVisibility(View.GONE);
        l3.setVisibility(View.GONE); 
        l4.setVisibility(View.GONE); 
        l5.setVisibility(View.GONE);
        l6.setVisibility(View.GONE);

        tv1.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l1.setVisibility(View.VISIBLE);
            }
        });
        tv2.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l2.setVisibility(View.VISIBLE);
            }
        });
        tv3.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l3.setVisibility(View.VISIBLE);

            }
        });
        tv4.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.GONE);
                l4.setVisibility(View.VISIBLE); 
            }
        });
        tv5.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l6.setVisibility(View.GONE);
                l5.setVisibility(View.VISIBLE); 
            }
        });
        tv6.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                l1.setVisibility(View.GONE);
                l2.setVisibility(View.GONE);
                l3.setVisibility(View.GONE); 
                l4.setVisibility(View.GONE); 
                l5.setVisibility(View.GONE);
                l6.setVisibility(View.VISIBLE);
            }
        });

    }
}

คำตอบ:


706

คุณสามารถทำสองสิ่งเพื่อเพิ่มแอนิเมชั่นก่อนอื่นคุณสามารถให้แอนดรอยด์แอนนิเมชั่นเปลี่ยนเค้าโครงให้คุณได้ ด้วยวิธีนี้ทุกครั้งที่คุณเปลี่ยนบางสิ่งในเลย์เอาต์เช่นการเปลี่ยนมุมมองการมองเห็นหรือมุมมองตำแหน่งแอนดรอยด์จะสร้างภาพเคลื่อนไหวจางหาย / การเปลี่ยนแปลงโดยอัตโนมัติ ในการใช้ชุดนั้น

android:animateLayoutChanges="true"

บนโหนดรูทในโครงร่างของคุณ

ตัวเลือกที่สองของคุณคือการเพิ่มภาพเคลื่อนไหวด้วยตนเอง สำหรับสิ่งนี้ฉันขอแนะนำให้คุณใช้ API ภาพเคลื่อนไหวใหม่ที่แนะนำใน Android 3.0 (Honeycomb) ฉันสามารถให้คุณตัวอย่าง:

สิ่งนี้จะจางหายไปView:

view.animate().alpha(0.0f);

มันจะจางหายไปใน:

view.animate().alpha(1.0f);

สิ่งนี้จะViewลดความสูงลงได้โดย:

view.animate().translationY(view.getHeight());

นี่จะคืนค่าViewไปยังตำแหน่งเริ่มต้นหลังจากย้ายไปที่อื่นแล้ว:

view.animate().translationY(0);

คุณยังสามารถใช้setDuration()เพื่อกำหนดระยะเวลาของภาพเคลื่อนไหว ตัวอย่างเช่นนี้จะจางหายViewไปในช่วงเวลา 2 วินาที:

view.animate().alpha(0.0f).setDuration(2000);

และคุณสามารถรวมแอนิเมชั่นได้มากเท่าที่คุณต้องการตัวอย่างเช่นมันจะจางหายไปViewและเลื่อนมันลงในเวลาเดียวกันในช่วงเวลา 0.3 วินาที:

view.animate()
        .translationY(view.getHeight())
        .alpha(0.0f)
        .setDuration(300);

และคุณยังสามารถกำหนดผู้ฟังให้กับอนิเมชั่นและตอบสนองต่อเหตุการณ์ทุกชนิด เช่นเดียวกับเมื่อภาพเคลื่อนไหวเริ่มขึ้นเมื่อมันจบลงหรือทำซ้ำเป็นต้นโดยใช้คลาสนามธรรมAnimatorListenerAdapterคุณไม่จำเป็นต้องใช้การเรียกกลับทั้งหมดAnimatorListenerในครั้งเดียว แต่มีเพียงสิ่งที่คุณต้องการ ทำให้โค้ดอ่านง่ายขึ้น ยกตัวอย่างเช่นจางหายรหัสต่อไปนี้ออกViewย้ายมันลงมาจากความสูงในช่วง 0.3 วินาที (300 มิลลิวินาที) View.GONEและเมื่อภาพเคลื่อนไหวจะทำการแสดงผลของมันจะถูกตั้งค่าให้เป็น

view.animate()
        .translationY(view.getHeight())
        .alpha(0.0f)
        .setDuration(300)
        .setListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                view.setVisibility(View.GONE);
            }
        });

6
@Natix ฉันจะไม่เรียกมันว่า super call redundant อย่าแก้ไขเพียงผิวเผินว่าไม่มีอะไรผิดปกติ
Xaver Kapeller

5
เป็นสิ่งที่ดี แต่สิ่งที่ตรงกันข้ามไม่ทำงานอย่างถูกต้องทำไม? view.setVisibility (View.VISIBLE); ด้วย alpha (1.0f) จะปรากฏขึ้นพร้อมกับช่องว่างด้านบน 100 ช่อง
delive

15
ต้องล้างภาพเคลื่อนไหวก่อนตั้งค่าการมองเห็น >> view.clearAnimation(); view.setVisibility(View.GONE);มิฉะนั้นโครงร่างจะยังคงมองไม่เห็นและไม่หายไป
Eftekhari

2
@Eftekhari พวกเขาไม่ได้ใช้ทรัพยากรอย่างเข้มข้น และหากคุณมีเวอร์ชั่น Android ที่ทันสมัย ​​แต่ก็ยังมีความล่าช้ากว่าที่คุณเคยมีโทรศัพท์รุ่นเก่าที่มีหน่วยความจำต่ำหรือชิปกราฟิกที่ไม่ดี และฉันไม่ได้พูดถึงห้องสมุดใหม่ แอนิเมชั่นเป็นของพื้นเมือง พวกเขาเป็นส่วนหนึ่งของ Android Framework พวกเขาได้รับการปล่อยตัวเมื่อ 5 ปีที่แล้วและวันนี้ 97.9% ของอุปกรณ์ทั้งหมดที่สนับสนุนพวกเขา ไม่มีเหตุผลที่จะไม่ใช้แอนิเมชั่นหรืออย่างน้อยViewCompat.animate()ซึ่งเป็นส่วนหนึ่งของห้องสมุดสนับสนุนและใช้แอนิเมเตอร์ในเวอร์ชั่นที่ใหม่กว่าและดูแอนิเมชั่นบน Android 3.0 และด้านล่าง
Xaver Kapeller

1
แต่เมื่อ 97.9% ของอุปกรณ์ทั้งหมดเป็น Android 4.0 ขึ้นไปจะไม่มีกรณีการใช้งานเหลือViewCompat.animate()อยู่มากมาย
Xaver Kapeller

70

วิธีที่ง่ายที่สุดในการVisibilityเปลี่ยนแปลงการเคลื่อนไหวคือการใช้Transition APIซึ่งมีอยู่ในแพ็คเกจสนับสนุน (androidx) เพียงแค่เรียกTransitionManager.beginDelayedTransitionวิธีการแล้วเปลี่ยนการมองเห็นของมุมมอง มีการเปลี่ยนค่าเริ่มต้นหลายประการเช่นมี,FadeSlide

import androidx.transition.TransitionManager;
import androidx.transition.Transition;
import androidx.transition.Fade;

private void toggle() {
    Transition transition = new Fade();
    transition.setDuration(600);
    transition.addTarget(R.id.image);

    TransitionManager.beginDelayedTransition(parent, transition);
    image.setVisibility(show ? View.VISIBLE : View.GONE);
}

จุดparentกำเนิดViewGroupของมุมมองภาพเคลื่อนไหวอยู่ที่ไหน ผลลัพธ์:

ป้อนคำอธิบายรูปภาพที่นี่

นี่คือผลSlideการเปลี่ยนแปลง:

import androidx.transition.Slide;

Transition transition = new Slide(Gravity.BOTTOM);

ป้อนคำอธิบายรูปภาพที่นี่

มันง่ายที่จะเขียนการเปลี่ยนแปลงที่กำหนดเองถ้าคุณต้องการอะไรที่แตกต่าง นี่คือตัวอย่างกับCircularRevealTransitionที่ผมเขียนไว้ในคำตอบอื่น มันแสดงและซ่อนมุมมองด้วยภาพเคลื่อนไหว CircularReveal

Transition transition = new CircularRevealTransition();

ป้อนคำอธิบายรูปภาพที่นี่

android:animateLayoutChanges="true"ตัวเลือกทำสิ่งเดียวกันมันใช้AutoTransitionเป็นการเปลี่ยนแปลง


@TouhidulIslam no คลาสนี้มีอยู่ในแพ็คเกจ androidx ทุกอย่างเข้ากันได้แบบย้อนกลับ
ashakirov

2
สิ่งที่เกี่ยวกับการขยาย / ยุบกลุ่มมุมมอง?
TheRealChx101

คุณสามารถทำหลายbeginDelayedTransitions?
Jeongbebs

26

กรุณาตรวจสอบนี้การเชื่อมโยง ซึ่งจะอนุญาตให้แอนิเมชันเช่น L2R, R2L, T2B, B2T

รหัสนี้แสดงภาพเคลื่อนไหวจากซ้ายไปขวา

TranslateAnimation animate = new TranslateAnimation(0,view.getWidth(),0,0);
animate.setDuration(500);
animate.setFillAfter(true);
view.startAnimation(animate);
view.setVisibility(View.GONE);

หากคุณต้องการทำจาก R2L ให้ใช้

TranslateAnimation animate = new TranslateAnimation(0,-view.getWidth(),0,0);

สำหรับบนลงล่างเป็น

TranslateAnimation animate = new TranslateAnimation(0,0,0,view.getHeight());

และในทางกลับกัน ..


8
สิ่งนี้จะแทนที่มุมมองจากตำแหน่งเดิม
Relm

24

ลองเพิ่มบรรทัดนี้ในเค้าโครงหลัก xml

 android:animateLayoutChanges="true"

เลย์เอาต์ของคุณจะมีลักษณะเช่นนี้

<?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:animateLayoutChanges="true"
    android:longClickable="false"
    android:orientation="vertical"
    android:weightSum="16">

    .......other code here

    </LinearLayout>

สิ่งนี้ใช้ได้สำหรับฉัน การตั้งค่าของฉันใช้เค้าโครงข้อ จำกัด เป็นมุมมองรูท เมื่อมุมมองถูกตั้งค่าเป็น View.VISIBLE ภาพเคลื่อนไหวจะปรากฏขึ้น
EdgeDev

วิธีการแก้ปัญหาที่เรียบง่ายและสง่างาม
Naveed Ahmad

11

จากคำตอบของ @Xaver Kapeller ฉันคิดหาวิธีในการสร้างภาพเคลื่อนไหวการเลื่อนเมื่อมุมมองใหม่ปรากฏบนหน้าจอ (และภาพเคลื่อนไหวเพื่อซ่อน)

มันมาจากสถานะนี้:

  • ปุ่ม
  • ปุ่มสุดท้าย

ถึง

  • ปุ่ม
  • ปุ่ม 1
  • ปุ่ม 2
  • ปุ่ม 3
  • ปุ่ม 4
  • ปุ่มสุดท้าย

และในทางกลับกัน.

ดังนั้นเมื่อผู้ใช้คลิกที่ปุ่มแรกองค์ประกอบ "ปุ่ม 1", "ปุ่ม 2", "ปุ่ม 3" และ "ปุ่ม 4" จะปรากฏขึ้นโดยใช้ภาพเคลื่อนไหวจางและองค์ประกอบ "ปุ่มสุดท้าย" จะเลื่อนลงมาจนจบ ความสูงของเลย์เอาต์จะเปลี่ยนเช่นกันทำให้สามารถใช้การเลื่อนดูได้อย่างถูกต้อง

นี่คือรหัสเพื่อแสดงองค์ประกอบที่มีภาพเคลื่อนไหว:

private void showElements() {
    // Precondition
    if (areElementsVisible()) {
        Log.w(TAG, "The view is already visible. Nothing to do here");
        return;
    }

    // Animate the hidden linear layout as visible and set
    // the alpha as 0.0. Otherwise the animation won't be shown
    mHiddenLinearLayout.setVisibility(View.VISIBLE);
    mHiddenLinearLayout.setAlpha(0.0f);
    mHiddenLinearLayout
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .alpha(1.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    updateShowElementsButton();
                    mHiddenLinearLayout.animate().setListener(null);
                }
            })
    ;

    mLastButton
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .translationY(mHiddenLinearLayoutHeight);

    // Update the high of all the elements relativeLayout
    LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();

    // TODO: Add vertical margins
    layoutParams.height = mLastButton.getHeight() + mHiddenLinearLayoutHeight;
}

และนี่คือรหัสเพื่อซ่อนองค์ประกอบของภาพเคลื่อนไหว:

private void hideElements() {
    // Precondition
    if (!areElementsVisible()) {
        Log.w(TAG, "The view is already non-visible. Nothing to do here");
        return;
    }

    // Animate the hidden linear layout as visible and set
    mHiddenLinearLayout
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .alpha(0.0f)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    Log.v(TAG, "Animation ended. Set the view as gone");
                    super.onAnimationEnd(animation);
                    mHiddenLinearLayout.setVisibility(View.GONE);
                    // Hack: Remove the listener. So it won't be executed when
                    // any other animation on this view is executed
                    mHiddenLinearLayout.animate().setListener(null);
                    updateShowElementsButton();
                }
            })
    ;

    mLastButton
            .animate()
            .setDuration(ANIMATION_TRANSITION_TIME)
            .translationY(0);

    // Update the high of all the elements relativeLayout
    LayoutParams layoutParams = mAllElementsRelativeLayout.getLayoutParams();

    // TODO: Add vertical margins
    layoutParams.height = mLastButton.getHeight();
}

หมายเหตุมีวิธีแฮ็คง่ายๆในการซ่อนภาพเคลื่อนไหว ในผู้ฟังแอนิเมชั่น mHiddenLinearLayout ฉันต้องลบตัวฟังออกโดยใช้:

mHiddenLinearLayout.animate().setListener(null);

นี่เป็นเพราะเมื่อผู้ฟังภาพเคลื่อนไหวถูกแนบไปกับมุมมองในครั้งต่อไปที่มีการดำเนินการภาพเคลื่อนไหวใด ๆ ในมุมมองนี้ผู้ฟังจะถูกดำเนินการเช่นกัน นี่อาจเป็นข้อผิดพลาดในตัวฟังการเคลื่อนไหว

ซอร์สโค้ดของโครงการอยู่บน GitHub: https://github.com/jiahaoliuliu/ViewsAnimated

การเข้ารหัสมีความสุข!

อัปเดต : สำหรับผู้ฟังที่แนบกับมุมมองควรลบออกหลังจากที่ภาพเคลื่อนไหวสิ้นสุดลง ทำได้โดยใช้

view.animate().setListener(null);

คำตอบนี้เป็นคำตอบที่ดีที่สุด
Naveen Kumar M

1
view.animate().setListener(null);คำสั่งบันทึกวันของฉัน นี่ดูเหมือนจะเป็นข้อผิดพลาดอย่างแน่นอน
Michal Vician

@MichalVician ดีใจที่ได้ทำ!
jiahao

8

ฉันสามารถแสดง / ซ่อนเมนูด้วยวิธีนี้:

MenuView.java (ขยาย FrameLayout)

private final int ANIMATION_DURATION = 500;

public void showMenu()
{
    setVisibility(View.VISIBLE);
    animate()
            .alpha(1f)
            .setDuration(ANIMATION_DURATION)
            .setListener(null);
}

private void hideMenu()
{
    animate()
            .alpha(0f)
            .setDuration(ANIMATION_DURATION)
            .setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    setVisibility(View.GONE);
                }
            });
}

แหล่ง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.