অ্যাকশন আইটেমের জন্য অ্যানিমেটেড আইকন


91

আমি আমার সমস্যার যথাযথ সমাধানের জন্য সর্বত্র সন্ধান করছি এবং আমি এখনও এটির সন্ধান করতে পারছি না। আমার কাছে একটি অ্যাকশনবার (অ্যাকশনবারেরলক) রয়েছে যা একটি মেনু সহ এক্সএমএল ফাইল থেকে স্ফীত হয় এবং সেই মেনুতে একটি আইটেম থাকে এবং সেই আইটেমটি অ্যাকশন আইটেম হিসাবে প্রদর্শিত হয়।

তালিকা:

<menu xmlns:android="http://schemas.android.com/apk/res/android" >    
    <item
        android:id="@+id/menu_refresh"       
        android:icon="@drawable/ic_menu_refresh"
        android:showAsAction="ifRoom"
        android:title="Refresh"/>    
</menu>

ক্রিয়াকলাপ:

[...]
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getSupportMenuInflater().inflate(R.menu.mymenu, menu);
    return true;
  }
[...]

অ্যাকশন আইটেমটি একটি আইকন এবং কোনও পাঠ্য সহ প্রদর্শিত হয় তবে ব্যবহারকারী যখন অ্যাকশন আইটেমটিতে ক্লিক করেন, আমি আইকনটি আরও নির্দিষ্ট করে, জায়গায় ঘোরানো শুরু করতে চাই anima প্রশ্নে থাকা আইকনটি রিফ্রেশ আইকন।

আমি বুঝতে পেরেছি যে অ্যাকশনবারের কাস্টম ভিউগুলি ব্যবহারের জন্য সমর্থন রয়েছে ( অ্যাকশন ভিউ যুক্ত করা ) তবে এই কাস্টম ভিউটি অ্যাকশনবারের পুরো অঞ্চলটি coverাকতে প্রসারিত করা হয়েছে এবং অ্যাপ্লিকেশন আইকনটি বাদ দিয়ে আসলে সমস্ত কিছুই অবরুদ্ধ করে দেয়, যা আমার ক্ষেত্রে আমি যা খুঁজছিলাম তা নয় which ।

সুতরাং আমার পরবর্তী প্রয়াসটি ছিল অ্যানিমেশনড্রেইবলটি ব্যবহার করার চেষ্টা এবং আমার অ্যানিমেশন ফ্রেম-বাই ফ্রেম সংজ্ঞায়িত করা, মেনু আইটেমটির জন্য আইকন হিসাবে অঙ্কনযোগ্য সেট করে এবং তারপরে onOptionsItemSelected(MenuItem item)আইকনটি পেতে এবং ব্যবহার করে অ্যানিমেটিং শুরু করা ((AnimationDrawable)item.getIcon()).start()। এটি অবশ্য ব্যর্থ হয়েছিল। কেউ কি এই প্রভাবটি সম্পাদন করার কোনও উপায় জানেন?

উত্তর:


174

আপনি সঠিক পথে আছেন এখানে গিটহাব গগস অ্যাপগুলি কীভাবে এটি প্রয়োগ করবে।

প্রথমে তারা একটি অ্যানিমেশন এক্সএমএল সংজ্ঞায়িত করে:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%"
    android:duration="1000"
    android:interpolator="@android:anim/linear_interpolator" />

এখন অ্যাকশন দেখার জন্য একটি বিন্যাস সংজ্ঞায়িত করুন:

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/ic_action_refresh"
    style="@style/Widget.Sherlock.ActionButton" />

আমাদের যখনই আইটেমটি ক্লিক করা হয় তখন এ দৃশ্যটি সক্ষম করা দরকার:

 public void refresh() {
     /* Attach a rotating ImageView to the refresh item as an ActionView */
     LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     ImageView iv = (ImageView) inflater.inflate(R.layout.refresh_action_view, null);

     Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.clockwise_refresh);
     rotation.setRepeatCount(Animation.INFINITE);
     iv.startAnimation(rotation);

     refreshItem.setActionView(iv);

     //TODO trigger loading
 }

লোডিং হয়ে গেলে, অ্যানিমেশনটি বন্ধ করুন এবং দেখুনটি সাফ করুন:

public void completeRefresh() {
    refreshItem.getActionView().clearAnimation();
    refreshItem.setActionView(null);
}

এবং তুমি করে ফেলেছ!

কিছু অতিরিক্ত জিনিস:

  • ক্রিয়া ভিউ লেআউট মুদ্রাস্ফীতি এবং অ্যানিমেশন মুদ্রাস্ফীতি ক্যাশে। এগুলি ধীরে ধীরে তাই আপনি কেবল একবারে এটি করতে চান।
  • nullচেক ইন যোগ করুনcompleteRefresh()

অ্যাপ্লিকেশনটিতে টানার অনুরোধটি এখানে: https://github.com/github/gauges-android/pull/13/files


4
পারফেক্ট! আমি অ্যান্ড্রয়েড ডক্স পৃষ্ঠায় ব্যবহৃত পদ্ধতিটি অনুসরণ করে চলেছি : একটি অ্যাকশনভিউ যুক্ত করা এবং সেই পদ্ধতিটির সাহায্যে পুরো এবিটি ব্লক হয়ে যায়। আবার আপনাকে ধন্যবাদ!
অ্যালেক্স ফু

4
দুর্দান্ত উত্তর, তবে getActivity () আর অ্যাক্সেসযোগ্য নয়, পরিবর্তে getApplication () ব্যবহার করুন।
theAlse

8
@ অ্যালবার্জ এটি সম্পূর্ণরূপে আপনার অ্যাপ্লিকেশনটির সাথে নির্দিষ্ট এবং কোনও সাধারণ নিয়ম নয়। আপনি রিফ্রেশ পদ্ধতিটি কোথায় রাখছেন তার উপরে এটি নির্ভরশীল।
জেক ওয়ার্টন

4
আপনার চিত্রটি বর্গক্ষেত্র এবং কোনও ক্রিয়া আইটেমের জন্য সঠিক আকারের হলে কোনও লাফ দেওয়া উচিত নয়।
জেক ওয়ার্টন

14
এটি বাস্তবায়নের সময় আমার পাশের বোতামটিও লাফিয়ে উঠতে সমস্যা হয়েছিল। এটি কারণ আমি উইজেট.শেরলক.অ্যাকশনবটন স্টাইলটি ব্যবহার করছিলাম না। আমি এটি যুক্ত করে android:paddingLeft="12dp"এবং android:paddingRight="12dp"আমার নিজের থিমটিতে সংশোধন করেছি।
উইলিয়াম কার্টার

16

অ্যাকশনবারারলক ব্যবহার করে সমাধানের জন্য আমি কিছুটা কাজ করেছি, আমি এটি নিয়ে এসেছি:

রেজ / লেআউট / অনির্দিষ্ট_প্রেস_অ্যাকশন.এক্সএমএল

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="48dp"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:paddingRight="12dp" >

    <ProgressBar
        style="@style/Widget.Sherlock.ProgressBar"
        android:layout_width="44dp"
        android:layout_height="32dp"
        android:layout_gravity="left"
        android:layout_marginLeft="12dp"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/rotation_refresh"
        android:paddingRight="12dp" />

</FrameLayout>

রেজ / লেআউট-ভি 11 / অনির্দিষ্ট_প্রেস_অ্যাকশন.এক্সএমএল

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

    <ProgressBar
        style="@style/Widget.Sherlock.ProgressBar"
        android:layout_width="32dp"
        android:layout_gravity="left"
        android:layout_marginRight="12dp"
        android:layout_marginLeft="12dp"
        android:layout_height="32dp"
        android:indeterminateDrawable="@drawable/rotation_refresh"
        android:indeterminate="true" />

</FrameLayout>

res / অঙ্কনযোগ্য / ঘূর্ণন_আরফ্রেশ.এক্সএমএল

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:pivotX="50%"
    android:pivotY="50%"
    android:drawable="@drawable/ic_menu_navigation_refresh"
    android:repeatCount="infinite" >

</rotate>

ক্রিয়াকলাপের কোড (আমার এটি ক্রিয়াকলাপবিহীনতার সাথে প্যারেন্ট ক্লাসে রয়েছে)

// Helper methods
protected MenuItem refreshItem = null;  

protected void setRefreshItem(MenuItem item) {
    refreshItem = item;
}

protected void stopRefresh() {
    if (refreshItem != null) {
        refreshItem.setActionView(null);
    }
}

protected void runRefresh() {
    if (refreshItem != null) {
        refreshItem.setActionView(R.layout.indeterminate_progress_action);
    }
}

মেনু আইটেম তৈরি কার্যকলাপ

private static final int MENU_REFRESH = 1;
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    menu.add(Menu.NONE, MENU_REFRESH, Menu.NONE, "Refresh data")
            .setIcon(R.drawable.ic_menu_navigation_refresh)
            .setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_ALWAYS);
    setRefreshItem(menu.findItem(MENU_REFRESH));
    refreshData();
    return super.onCreateOptionsMenu(menu);
}

private void refreshData(){
    runRefresh();
    // work with your data
    // for animation to work properly, make AsyncTask to refresh your data
    // or delegate work anyhow to another thread
    // If you'll have work at UI thread, animation might not work at all
    stopRefresh();
}

এবং আইকন, এই হয় drawable-xhdpi/ic_menu_navigation_refresh.png
অঙ্কনযোগ্য-এক্সএইচডিপি / আইসি_মেনু_নাভিগেশন_রেফ্রেশ.পিএনজি

এটি HTTP- র মধ্যে পাওয়া যেতে পারে


এফওয়াইআই আমাকে একটি অ্যান্ড্রয়েডের সাথে লেআউট-টিভিডিপি-ভি 11 / অনির্দিষ্ট_প্রেগ্রেস_অ্যাকশন.এক্সএমএল যুক্ত করতে হয়েছিল: লেআউট_মার্জাইনরাইট = "16 ডিপি", সঠিকভাবে প্রদর্শন করতে। আমি জানি না যে এই কোডটি আমার কোড, এবিএস, বা এসডিকে কোনও বাগ আছে।
ইরাক্লিস

আমি আমার কয়েকটি অ্যাপ্লিকেশন দিয়ে এই সমাধানটি পরীক্ষা করে দেখেছি এবং তারা সকলেই একই কোড ব্যবহার করে। সুতরাং আমার ধারণা এটি আপনার কোডে কিছুটা অসঙ্গতি, কারণ এবিএস (৪.২.০) এবং এসডিকে (এপিআই ১৪ এবং উচ্চতর) ভাগ করা হয়েছে ;-)
মেরেক সেবেরা

আপনি কি এটি একটি নেক্সাস 7 এ চেষ্টা করেছেন? (কোনও ইমু নয়, আসল ডিভাইস) এটির একমাত্র ডিভাইস এটি সঠিকভাবে প্রদর্শন করছে না, তাই টিভিপিপি সেটিংস।
ইরাক্লিস

@ ইরাকলিস না, আমার কাছে এমন ডিভাইস নেই। হ্যাঁ, এখন আমি দেখতে পাচ্ছি, আপনি কি ডিবাগ করেছেন। দুর্দান্ত, উত্তরের সাথে এটির সংযোজন করতে দ্বিধা বোধ করুন।
মারেক সেবেরা

6

জ্যাক ওয়ার্টন যা বলেছিলেন তা ছাড়াও, অ্যানিমেশনটি সুস্পষ্টভাবে বন্ধ হয়ে যায় এবং লোডিং শেষ হওয়ার সাথে সাথে চারপাশে লাফিয়ে না যায় তা নিশ্চিত করার জন্য আপনাকে নিম্নলিখিতটি করা উচিত ।

প্রথমে একটি নতুন বুলিয়ান তৈরি করুন (পুরো শ্রেণীর জন্য):

private boolean isCurrentlyLoading;

আপনার বোঝা শুরু করার পদ্ধতিটি সন্ধান করুন। ক্রিয়াকলাপটি লোড হওয়া শুরু হওয়ার পরে আপনার বুলিয়ানটিকে সত্যে সেট করুন।

isCurrentlyLoading = true;

আপনার লোডিং শেষ হয়ে গেলে যে পদ্ধতিটি শুরু হয়েছিল তা সন্ধান করুন। অ্যানিমেশনটি সাফ করার পরিবর্তে আপনার বুলিয়ানটিকে মিথ্যাতে সেট করুন।

isCurrentlyLoading = false;

আপনার অ্যানিমেশনটিতে একটি অ্যানিমেশনলিস্টনার সেট করুন:

animationRotate.setAnimationListener(new AnimationListener() {

তারপরে, প্রতিবার অ্যানিমেশনটি একবারে কার্যকর করা হয়েছিল, এর অর্থ যখন আপনার আইকনটি একটি ঘূর্ণায়মান হবে, লোডিংয়ের অবস্থাটি পরীক্ষা করুন এবং যদি আর লোড না হয় তবে অ্যানিমেশনটি বন্ধ হয়ে যাবে।

@Override
public void onAnimationRepeat(Animation animation) {
    if(!isCurrentlyLoading) {
        refreshItem.getActionView().clearAnimation();
        refreshItem.setActionView(null);
    }
}

এইভাবে, অ্যানিমেশনটি কেবল তখনই থামানো যাবে যদি এটি ইতিমধ্যে শেষ অবধি ঘোরানো হয় এবং শীঘ্রই পুনরাবৃত্তি করা হবে এবং এটি আর লোড হচ্ছে না।

আমি যখন জ্যাকের ধারণাটি বাস্তবায়িত করতে চাইছিলাম তখন এটি আমি অন্তত ছিলাম।


2

কোডে ঘূর্ণন তৈরির জন্য একটি বিকল্পও রয়েছে। সম্পূর্ণ স্নিপ:

    MenuItem item = getToolbar().getMenu().findItem(Menu.FIRST);
    if (item == null) return;

    // define the animation for rotation
    Animation animation = new RotateAnimation(0.0f, 360.0f,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
    animation.setDuration(1000);
    //animRotate = AnimationUtils.loadAnimation(this, R.anim.rotation);

    animation.setRepeatCount(Animation.INFINITE);

    ImageView imageView = new ImageView(this);
    imageView.setImageDrawable(UIHelper.getIcon(this, MMEXIconFont.Icon.mmx_refresh));

    imageView.startAnimation(animation);
    item.setActionView(imageView);

এটি ব্যবহার করে এবং অপশন আইটেমসলেক্টড ট্যাপটি কল করা হবে না।
সিউডোজাচ

1

সমর্থন লাইব্রেরির সাহায্যে আমরা কাস্টম অ্যাকশনভিউ ছাড়াই আইকনটি প্রাণবন্ত করতে পারি।

private AnimationDrawableWrapper drawableWrapper;    

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    //inflate menu...

    MenuItem menuItem = menu.findItem(R.id.your_icon);
    Drawable icon = menuItem.getIcon();
    drawableWrapper = new AnimationDrawableWrapper(getResources(), icon);
    menuItem.setIcon(drawableWrapper);
    return true;
}

public void startRotateIconAnimation() {
    ValueAnimator animator = ObjectAnimator.ofInt(0, 360);
    animator.addUpdateListener(animation -> {
        int rotation = (int) animation.getAnimatedValue();
        drawableWrapper.setRotation(rotation);
    });
    animator.start();
}

আমরা সরাসরি অঙ্কনীয় অ্যানিমেট করতে পারি না, সুতরাং অঙ্কনযোগ্য র্যাপার ব্যবহার করুন (API <21 এর জন্য android.support.v7 থেকে):

public class AnimationDrawableWrapper extends DrawableWrapper {

    private float rotation;
    private Rect bounds;

    public AnimationDrawableWrapper(Resources resources, Drawable drawable) {
        super(vectorToBitmapDrawableIfNeeded(resources, drawable));
        bounds = new Rect();
    }

    @Override
    public void draw(Canvas canvas) {
        copyBounds(bounds);
        canvas.save();
        canvas.rotate(rotation, bounds.centerX(), bounds.centerY());
        super.draw(canvas);
        canvas.restore();
    }

    public void setRotation(float degrees) {
        this.rotation = degrees % 360;
        invalidateSelf();
    }

    /**
     * Workaround for issues related to vector drawables rotation and scaling:
     * https://code.google.com/p/android/issues/detail?id=192413
     * https://code.google.com/p/android/issues/detail?id=208453
     */
    private static Drawable vectorToBitmapDrawableIfNeeded(Resources resources, Drawable drawable) {
        if (drawable instanceof VectorDrawable) {
            Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas c = new Canvas(b);
            drawable.setBounds(0, 0, c.getWidth(), c.getHeight());
            drawable.draw(c);
            drawable = new BitmapDrawable(resources, b);
        }
        return drawable;
    }
}

আমি এখান থেকে ড্রয়যোগ্য র্যাপার জন্য ধারণা নিয়েছি: https://stackoverflow.com/a/39108111/5541688


0

এটি আমার খুব সাধারণ সমাধান (উদাহরণস্বরূপ, কিছু রিফ্যাক্টর প্রয়োজন) স্ট্যান্ডার্ড মেনুআইটেমের সাথে কাজ করে, আপনি এটিকে কোনও সংখ্যা, আইকন, অ্যানিমেশন, যুক্তি ইত্যাদির সাথে ব্যবহার করতে পারেন

ক্রিয়াকলাপ শ্রেণিতে:

private enum RefreshMode {update, actual, outdated} 

স্ট্যান্ডার্ড শ্রোতা:

public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.menu_refresh: {
            refreshData(null);
            break;
        }
    }
}

রিফ্রেশডাটাতে () এর মতো কিছু করুন:

setRefreshIcon(RefreshMode.update);
// update your data
setRefreshIcon(RefreshMode.actual);

আইকনের জন্য বর্ণ বা অ্যানিমেশন নির্ধারণের জন্য পদ্ধতি:

 void setRefreshIcon(RefreshMode refreshMode) {

    LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    Animation rotation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.rotation);
    FrameLayout iconView;

    switch (refreshMode) {
        case update: {
            iconView = (FrameLayout) inflater.inflate(R.layout.refresh_action_view,null);
            iconView.startAnimation(rotation);
            toolbar.getMenu().findItem(R.id.menu_refresh).setActionView(iconView);
            break;
        }
        case actual: {
            toolbar.getMenu().findItem(R.id.menu_refresh).getActionView().clearAnimation();
            iconView = (FrameLayout) inflater.inflate(R.layout.refresh_action_view_actual,null);
            toolbar.getMenu().findItem(R.id.menu_refresh).setActionView(null);
            toolbar.getMenu().findItem(R.id.menu_refresh).setIcon(R.drawable.ic_refresh_24dp_actual);
            break;
        }
        case outdated:{
            toolbar.getMenu().findItem(R.id.menu_refresh).setIcon(R.drawable.ic_refresh_24dp);
            break;
        }
        default: {
        }
    }
}

আইকন সহ 2 টি লেআউট রয়েছে (R.layout.refresh_action_view (+ "_actual")):

<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:gravity="center">
<ImageView
    android:src="@drawable/ic_refresh_24dp_actual" // or ="@drawable/ic_refresh_24dp"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_margin="12dp"/>
</FrameLayout>

এক্ষেত্রে স্ট্যান্ডার্ড ঘোরানো অ্যানিমেশন (R.anim.rotation):

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="1000"
android:repeatCount="infinite"
/>

0

সবচেয়ে ভাল উপায় এখানে:

public class HomeActivity extends AppCompatActivity {
    public static ActionMenuItemView btsync;
    public static RotateAnimation rotateAnimation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    rotateAnimation = new RotateAnimation(360, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
    rotateAnimation.setDuration((long) 2*500);
    rotateAnimation.setRepeatCount(Animation.INFINITE);

এবং তারপর:

private void sync() {
    btsync = this.findViewById(R.id.action_sync); //remember that u cant access this view at onCreate() or onStart() or onResume() or onPostResume() or onPostCreate() or onCreateOptionsMenu() or onPrepareOptionsMenu()
    if (isSyncServiceRunning(HomeActivity.this)) {
        showConfirmStopDialog();
    } else {
        if (btsync != null) {
            btsync.startAnimation(rotateAnimation);
        }
        Context context = getApplicationContext();
        context.startService(new Intent(context, SyncService.class));
    }
}

মনে রাখবেন যে আপনি "btsync = this.findViewById (R.id.action_sync) অ্যাক্সেস করতে পারবেন না;" onCreate () বা onStart () অথবা onResume () অথবা onPostResume () অথবা onPostCreate () অথবা onCreateOptionsMenu () বা onPrepareOptionsMenu () এ আপনি যদি চান তবে যদি কার্যকলাপ শুরু হওয়ার কিছুক্ষণ পরে এটি পোস্টডলেডে রেখে দিন:

public static void refreshSync(Activity context) {
    Handler handler = new Handler(Looper.getMainLooper());
    handler.postDelayed(new Runnable() {
        public void run() {
            btsync = context.findViewById(R.id.action_sync);
            if (btsync != null && isSyncServiceRunning(context)) {
                btsync.startAnimation(rotateAnimation);
            } else if (btsync != null) {
                btsync.clearAnimation();
            }
        }
    }, 1000);
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.