zoukankan      html  css  js  c++  java
  • Android控件

    package com.yalantis.euclid.library;

    import android.animation.Animator;
    import android.animation.AnimatorSet;
    import android.animation.ObjectAnimator;
    import android.app.Activity;
    import android.graphics.RectF;
    import android.graphics.drawable.ShapeDrawable;
    import android.graphics.drawable.shapes.RoundRectShape;
    import android.os.Bundle;
    import android.view.View;
    import android.view.ViewGroup;
    import android.view.animation.AccelerateDecelerateInterpolator;
    import android.view.animation.AccelerateInterpolator;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.view.animation.DecelerateInterpolator;
    import android.widget.AdapterView;
    import android.widget.BaseAdapter;
    import android.widget.FrameLayout;
    import android.widget.ImageView;
    import android.widget.LinearLayout;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.TextView;

    import com.nhaarman.listviewanimations.appearance.ViewAnimator;
    import com.nhaarman.listviewanimations.appearance.simple.SwingLeftInAnimationAdapter;
    import com.squareup.picasso.Picasso;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;

    import io.codetail.animation.SupportAnimator;
    import io.codetail.animation.ViewAnimationUtils;

    /**

    • Created by Oleksii Shliama on 1/27/15.
      */
      public abstract class EuclidActivity extends Activity {

      private static final int REVEAL_ANIMATION_DURATION = 1000;
      private static final int MAX_DELAY_SHOW_DETAILS_ANIMATION = 500;
      private static final int ANIMATION_DURATION_SHOW_PROFILE_DETAILS = 500;
      private static final int STEP_DELAY_HIDE_DETAILS_ANIMATION = 80;
      private static final int ANIMATION_DURATION_CLOSE_PROFILE_DETAILS = 500;
      private static final int ANIMATION_DURATION_SHOW_PROFILE_BUTTON = 300;
      private static final int CIRCLE_RADIUS_DP = 50;

      protected RelativeLayout mWrapper;
      protected ListView mListView;
      protected FrameLayout mToolbar;
      protected RelativeLayout mToolbarProfile;
      protected LinearLayout mProfileDetails;
      protected TextView mTextViewProfileName;
      protected TextView mTextViewProfileDescription;
      protected View mButtonProfile;

      public static ShapeDrawable sOverlayShape;
      static int sScreenWidth;
      static int sProfileImageHeight;

      private SwingLeftInAnimationAdapter mListViewAnimationAdapter;
      private ViewAnimator mListViewAnimator;

      private View mOverlayListItemView;
      private EuclidState mState = EuclidState.Closed;

      private float mInitialProfileButtonX;

      private AnimatorSet mOpenProfileAnimatorSet;
      private AnimatorSet mCloseProfileAnimatorSet;
      private Animation mProfileButtonShowAnimation;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_euclid);

       mWrapper = (RelativeLayout) findViewById(R.id.wrapper);
       mListView = (ListView) findViewById(R.id.list_view);
       mToolbar = (FrameLayout) findViewById(R.id.toolbar_list);
       mToolbarProfile = (RelativeLayout) findViewById(R.id.toolbar_profile);
       mProfileDetails = (LinearLayout) findViewById(R.id.wrapper_profile_details);
       mTextViewProfileName = (TextView) findViewById(R.id.text_view_profile_name);
       mTextViewProfileDescription = (TextView) findViewById(R.id.text_view_profile_description);
       mButtonProfile = findViewById(R.id.button_profile);
       mButtonProfile.post(new Runnable() {
           @Override
           public void run() {
               mInitialProfileButtonX = mButtonProfile.getX();
           }
       });
       findViewById(R.id.toolbar_profile_back).setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View v) {
               animateCloseProfileDetails();
           }
       });
      
       sScreenWidth = getResources().getDisplayMetrics().widthPixels;
       sProfileImageHeight = getResources().getDimensionPixelSize(R.dimen.height_profile_image);
       sOverlayShape = buildAvatarCircleOverlay();
      
       initList();
      

      }

      private void initList() {
      mListViewAnimationAdapter = new SwingLeftInAnimationAdapter(getAdapter());
      mListViewAnimationAdapter.setAbsListView(mListView);
      mListViewAnimator = mListViewAnimationAdapter.getViewAnimator();
      if (mListViewAnimator != null) {
      mListViewAnimator.setAnimationDurationMillis(getAnimationDurationCloseProfileDetails());
      mListViewAnimator.disableAnimations();
      }
      mListView.setAdapter(mListViewAnimationAdapter);
      mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
      @Override
      public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
      mState = EuclidState.Opening;
      showProfileDetails((Map<String, Object>) parent.getItemAtPosition(position), view);
      }
      });
      }

      /**

      • This method counts delay before profile toolbar and profile details start their transition

      • animations, depending on clicked list item on-screen position.

      • @param item - data from adapter, that will be set into overlay view.

      • @param view - clicked view.
        */
        private void showProfileDetails(Map<String, Object> item, final View view) {
        mListView.setEnabled(false);

        int profileDetailsAnimationDelay = getMaxDelayShowDetailsAnimation() * Math.abs(view.getTop())
        / sScreenWidth;

        addOverlayListItem(item, view);
        startRevealAnimation(profileDetailsAnimationDelay);
        animateOpenProfileDetails(profileDetailsAnimationDelay);
        }

      /**

      • This method inflates a clone of clicked view directly above it. Sets data into it.

      • @param item - data from adapter, that will be set into overlay view.

      • @param view - clicked view.
        */
        private void addOverlayListItem(Map<String, Object> item, View view) {
        if (mOverlayListItemView == null) {
        mOverlayListItemView = getLayoutInflater().inflate(R.layout.overlay_list_item, mWrapper, false);
        } else {
        mWrapper.removeView(mOverlayListItemView);
        }

        mOverlayListItemView.findViewById(R.id.view_avatar_overlay).setBackground(sOverlayShape);

        Picasso.with(EuclidActivity.this).load((Integer) item.get(EuclidListAdapter.KEY_AVATAR))
        .resize(sScreenWidth, sProfileImageHeight).centerCrop()
        .placeholder(R.color.blue)
        .into((ImageView) mOverlayListItemView.findViewById(R.id.image_view_reveal_avatar));
        Picasso.with(EuclidActivity.this).load((Integer) item.get(EuclidListAdapter.KEY_AVATAR))
        .resize(sScreenWidth, sProfileImageHeight).centerCrop()
        .placeholder(R.color.blue)
        .into((ImageView) mOverlayListItemView.findViewById(R.id.image_view_avatar));

        ((TextView) mOverlayListItemView.findViewById(R.id.text_view_name)).setText((String) item.get(EuclidListAdapter.KEY_NAME));
        ((TextView) mOverlayListItemView.findViewById(R.id.text_view_description)).setText((String) item.get(EuclidListAdapter.KEY_DESCRIPTION_SHORT));
        setProfileDetailsInfo(item);

        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.topMargin = view.getTop() + mToolbar.getHeight();
        params.bottomMargin = -(view.getBottom() - mListView.getHeight());
        mWrapper.addView(mOverlayListItemView, params);
        mToolbar.bringToFront();
        }

      /**

      • This method sets data of the clicked list item to profile details view.
      • @param item - data from adapter, that will be set into overlay view.
        */
        private void setProfileDetailsInfo(Map<String, Object> item) {
        mTextViewProfileName.setText((String) item.get(EuclidListAdapter.KEY_NAME));
        mTextViewProfileDescription.setText((String) item.get(EuclidListAdapter.KEY_DESCRIPTION_FULL));
        }

      /**

      • This method starts circle reveal animation on list item overlay view, to show full-sized
      • avatar image underneath it. And starts transition animation to position clicked list item
      • under the toolbar.
      • @param profileDetailsAnimationDelay - delay before profile toolbar and profile details start their transition
      •                                 animations.
        

      */
      private void startRevealAnimation(final int profileDetailsAnimationDelay) {
      mOverlayListItemView.post(new Runnable() {
      @Override
      public void run() {
      getAvatarRevealAnimator().start();
      getAvatarShowAnimator(profileDetailsAnimationDelay).start();
      }
      });
      }

      /**

      • This method creates and setups circle reveal animation on list item overlay view.

      • @return - animator object that starts circle reveal animation.
        */
        private SupportAnimator getAvatarRevealAnimator() {
        final LinearLayout mWrapperListItemReveal = (LinearLayout) mOverlayListItemView.findViewById(R.id.wrapper_list_item_reveal);

        int finalRadius = Math.max(mOverlayListItemView.getWidth(), mOverlayListItemView.getHeight());

        final SupportAnimator mRevealAnimator = ViewAnimationUtils.createCircularReveal(
        mWrapperListItemReveal,
        sScreenWidth / 2,
        sProfileImageHeight / 2,
        dpToPx(getCircleRadiusDp() * 2),
        finalRadius);
        mRevealAnimator.setDuration(getRevealAnimationDuration());
        mRevealAnimator.addListener(new SupportAnimator.AnimatorListener() {
        @Override
        public void onAnimationStart() {
        mWrapperListItemReveal.setVisibility(View.VISIBLE);
        mOverlayListItemView.setX(0);
        }

         @Override
         public void onAnimationEnd() {
        
         }
        
         @Override
         public void onAnimationCancel() {
        
         }
        
         @Override
         public void onAnimationRepeat() {
        
         }
        

        });
        return mRevealAnimator;
        }

      /**

      • This method creates transition animation to move clicked list item under the toolbar.
      • @param profileDetailsAnimationDelay - delay before profile toolbar and profile details start their transition
      •                                 animations.
        
      • @return - animator object that starts transition animation.
        */
        private Animator getAvatarShowAnimator(int profileDetailsAnimationDelay) {
        final Animator mAvatarShowAnimator = ObjectAnimator.ofFloat(mOverlayListItemView, View.Y, mOverlayListItemView.getTop(), mToolbarProfile.getBottom());
        mAvatarShowAnimator.setDuration(profileDetailsAnimationDelay + getAnimationDurationShowProfileDetails());
        mAvatarShowAnimator.setInterpolator(new DecelerateInterpolator());
        return mAvatarShowAnimator;
        }

      /**

      • This method starts set of transition animations, which show profile toolbar and profile
      • details views, right after the passed delay.
      • @param profileDetailsAnimationDelay - delay before profile toolbar and profile details
      •                                 start their transition animations.
        

      */
      private void animateOpenProfileDetails(int profileDetailsAnimationDelay) {
      createOpenProfileButtonAnimation();
      getOpenProfileAnimatorSet(profileDetailsAnimationDelay).start();
      }

      /**

      • This method creates if needed the set of transition animations, which show profile toolbar and profile

      • details views, right after the passed delay.

      • @param profileDetailsAnimationDelay- delay before profile toolbar and profile details

      •                                  start their transition animations.
        
      • @return - animator set that starts transition animations.
        */
        private AnimatorSet getOpenProfileAnimatorSet(int profileDetailsAnimationDelay) {
        if (mOpenProfileAnimatorSet == null) {
        List profileAnimators = new ArrayList<>();
        profileAnimators.add(getOpenProfileToolbarAnimator());
        profileAnimators.add(getOpenProfileDetailsAnimator());

         mOpenProfileAnimatorSet = new AnimatorSet();
         mOpenProfileAnimatorSet.playTogether(profileAnimators);
         mOpenProfileAnimatorSet.setDuration(getAnimationDurationShowProfileDetails());
        

        }
        mOpenProfileAnimatorSet.setStartDelay(profileDetailsAnimationDelay);
        mOpenProfileAnimatorSet.setInterpolator(new DecelerateInterpolator());
        return mOpenProfileAnimatorSet;
        }

      /**

      • This method, if needed, creates and setups animation of scaling button from 0 to 1.
        */
        private void createOpenProfileButtonAnimation() {
        if (mProfileButtonShowAnimation == null) {
        mProfileButtonShowAnimation = AnimationUtils.loadAnimation(this, R.anim.profile_button_scale);
        mProfileButtonShowAnimation.setDuration(getAnimationDurationShowProfileButton());
        mProfileButtonShowAnimation.setInterpolator(new AccelerateInterpolator());
        mProfileButtonShowAnimation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        mButtonProfile.setVisibility(View.VISIBLE);
        }

             @Override
             public void onAnimationEnd(Animation animation) {
        
             }
        
             @Override
             public void onAnimationRepeat(Animation animation) {
        
             }
         });
        

        }
        }

      /**

      • This method creates and setups animator which shows profile toolbar.

      • @return - animator object.
        */
        private Animator getOpenProfileToolbarAnimator() {
        Animator mOpenProfileToolbarAnimator = ObjectAnimator.ofFloat(mToolbarProfile, View.Y, -mToolbarProfile.getHeight(), 0);
        mOpenProfileToolbarAnimator.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        mToolbarProfile.setX(0);
        mToolbarProfile.bringToFront();
        mToolbarProfile.setVisibility(View.VISIBLE);
        mProfileDetails.setX(0);
        mProfileDetails.bringToFront();
        mProfileDetails.setVisibility(View.VISIBLE);

             mButtonProfile.setX(mInitialProfileButtonX);
             mButtonProfile.bringToFront();
         }
        
         @Override
         public void onAnimationEnd(Animator animation) {
             mButtonProfile.startAnimation(mProfileButtonShowAnimation);
        
             mState = EuclidState.Opened;
         }
        
         @Override
         public void onAnimationCancel(Animator animation) {
        
         }
        
         @Override
         public void onAnimationRepeat(Animator animation) {
        
         }
        

        });
        return mOpenProfileToolbarAnimator;
        }

      /**

      • This method creates animator which shows profile details.
      • @return - animator object.
        */
        private Animator getOpenProfileDetailsAnimator() {
        Animator mOpenProfileDetailsAnimator = ObjectAnimator.ofFloat(mProfileDetails, View.Y,
        getResources().getDisplayMetrics().heightPixels,
        getResources().getDimensionPixelSize(R.dimen.height_profile_picture_with_toolbar));
        return mOpenProfileDetailsAnimator;
        }

      /**

      • This method starts set of transition animations, which hides profile toolbar, profile avatar
      • and profile details views.
        */
        private void animateCloseProfileDetails() {
        mState = EuclidState.Closing;
        getCloseProfileAnimatorSet().start();
        }

      /**

      • This method creates if needed the set of transition animations, which hides profile toolbar, profile avatar

      • and profile details views. Also it calls notifyDataSetChanged() on the ListView's adapter,

      • so it starts slide-in left animation on list items.

      • @return - animator set that starts transition animations.
        */
        private AnimatorSet getCloseProfileAnimatorSet() {
        if (mCloseProfileAnimatorSet == null) {
        Animator profileToolbarAnimator = ObjectAnimator.ofFloat(mToolbarProfile, View.X,
        0, mToolbarProfile.getWidth());

         Animator profilePhotoAnimator = ObjectAnimator.ofFloat(mOverlayListItemView, View.X,
                 0, mOverlayListItemView.getWidth());
         profilePhotoAnimator.setStartDelay(getStepDelayHideDetailsAnimation());
        
         Animator profileButtonAnimator = ObjectAnimator.ofFloat(mButtonProfile, View.X,
                 mInitialProfileButtonX, mOverlayListItemView.getWidth() + mInitialProfileButtonX);
         profileButtonAnimator.setStartDelay(getStepDelayHideDetailsAnimation() * 2);
        
         Animator profileDetailsAnimator = ObjectAnimator.ofFloat(mProfileDetails, View.X,
                 0, mToolbarProfile.getWidth());
         profileDetailsAnimator.setStartDelay(getStepDelayHideDetailsAnimation() * 2);
        
         List<Animator> profileAnimators = new ArrayList<>();
         profileAnimators.add(profileToolbarAnimator);
         profileAnimators.add(profilePhotoAnimator);
         profileAnimators.add(profileButtonAnimator);
         profileAnimators.add(profileDetailsAnimator);
        
         mCloseProfileAnimatorSet = new AnimatorSet();
         mCloseProfileAnimatorSet.playTogether(profileAnimators);
         mCloseProfileAnimatorSet.setDuration(getAnimationDurationCloseProfileDetails());
         mCloseProfileAnimatorSet.setInterpolator(new AccelerateInterpolator());
         mCloseProfileAnimatorSet.addListener(new Animator.AnimatorListener() {
             @Override
             public void onAnimationStart(Animator animation) {
                 if (mListViewAnimator != null) {
                     mListViewAnimator.reset();
                     mListViewAnimationAdapter.notifyDataSetChanged();
                 }
             }
        
             @Override
             public void onAnimationEnd(Animator animation) {
                 mToolbarProfile.setVisibility(View.INVISIBLE);
                 mButtonProfile.setVisibility(View.INVISIBLE);
                 mProfileDetails.setVisibility(View.INVISIBLE);
        
                 mListView.setEnabled(true);
                 mListViewAnimator.disableAnimations();
        
                 mState = EuclidState.Closed;
             }
        
             @Override
             public void onAnimationCancel(Animator animation) {
        
             }
        
             @Override
             public void onAnimationRepeat(Animator animation) {
        
             }
         });
        

        }
        return mCloseProfileAnimatorSet;
        }

      /**

      • This method creates a view with empty/transparent circle in it's center. This view is used

      • to cover the profile avatar.

      • @return - ShapeDrawable object.
        */
        private ShapeDrawable buildAvatarCircleOverlay() {
        int radius = 666;
        ShapeDrawable overlay = new ShapeDrawable(new RoundRectShape(null,
        new RectF(
        sScreenWidth / 2 - dpToPx(getCircleRadiusDp() * 2),
        sProfileImageHeight / 2 - dpToPx(getCircleRadiusDp() * 2),
        sScreenWidth / 2 - dpToPx(getCircleRadiusDp() * 2),
        sProfileImageHeight / 2 - dpToPx(getCircleRadiusDp() * 2)),
        new float[]{radius, radius, radius, radius, radius, radius, radius, radius}));
        overlay.getPaint().setColor(getResources().getColor(R.color.gray));

        return overlay;
        }

      public int dpToPx(int dp) {
      return Math.round((float) dp * getResources().getDisplayMetrics().density);
      }

      @Override
      public void onBackPressed() {
      if (getState() == EuclidState.Opened) {
      animateCloseProfileDetails();
      } else if (getState() == EuclidState.Closed) {
      super.onBackPressed();
      }
      }

      /**

      • To use EuclidActivity class, at least this method must be implemented, with your own data.
      • @return - adapter with data. Check {@link com.yalantis.euclid.library.EuclidListAdapter}
        */
        protected abstract BaseAdapter getAdapter();

      /**

      • Returns current profile details state.
      • @return - {@link com.yalantis.euclid.library.EuclidState}
        */
        public EuclidState getState() {
        return mState;
        }

      /**

      • Duration of circle reveal animation.
      • @return - duration in milliseconds.
        */
        protected int getRevealAnimationDuration() {
        return REVEAL_ANIMATION_DURATION;
        }

      /**

      • Maximum delay between list item click and start of profile toolbar and profile details
      • transition animations. If clicked list item was positioned right at the top - we start
      • profile toolbar and profile details transition animations immediately, otherwise increase
      • start delay up to this value.
      • @return - duration in milliseconds.
        */
        protected int getMaxDelayShowDetailsAnimation() {
        return MAX_DELAY_SHOW_DETAILS_ANIMATION;
        }

      /**

      • Duration of profile toolbar and profile details transition animations.
      • @return - duration in milliseconds.
        */
        protected int getAnimationDurationShowProfileDetails() {
        return ANIMATION_DURATION_SHOW_PROFILE_DETAILS;
        }

      /**

      • Duration of delay between profile toolbar, profile avatar and profile details close animations.
      • @return - duration in milliseconds.
        */
        protected int getStepDelayHideDetailsAnimation() {
        return STEP_DELAY_HIDE_DETAILS_ANIMATION;
        }

      /**

      • Duration of profile details close animation.
      • @return - duration in milliseconds.
        */
        protected int getAnimationDurationCloseProfileDetails() {
        return ANIMATION_DURATION_CLOSE_PROFILE_DETAILS;
        }

      protected int getAnimationDurationShowProfileButton() {
      return ANIMATION_DURATION_SHOW_PROFILE_BUTTON;
      }

      /**

      • Radius of empty circle inside the avatar overlay.
      • @return - size dp.
        */
        protected int getCircleRadiusDp() {
        return CIRCLE_RADIUS_DP;
        }

    }
    package com.yalantis.euclid.library;

    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ArrayAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;

    import com.squareup.picasso.Picasso;

    import java.util.List;
    import java.util.Map;

    /**

    • Created by Oleksii Shliama on 1/27/15.
      */
      public class EuclidListAdapter extends ArrayAdapter<Map<String, Object>> {

      public static final String KEY_AVATAR = "avatar";
      public static final String KEY_NAME = "name";
      public static final String KEY_DESCRIPTION_SHORT = "description_short";
      public static final String KEY_DESCRIPTION_FULL = "description_full";

      private final LayoutInflater mInflater;
      private List<Map<String, Object>> mData;

      public EuclidListAdapter(Context context, int layoutResourceId, List<Map<String, Object>> data) {
      super(context, layoutResourceId, data);
      mData = data;
      mInflater = LayoutInflater.from(context);
      }

      @Override
      public View getView(int position, View convertView, ViewGroup parent) {
      final ViewHolder viewHolder;
      if (convertView == null) {
      convertView = mInflater.inflate(R.layout.list_item, parent, false);
      viewHolder = new ViewHolder();
      viewHolder.mViewOverlay = convertView.findViewById(R.id.view_avatar_overlay);
      viewHolder.mListItemAvatar = (ImageView) convertView.findViewById(R.id.image_view_avatar);
      viewHolder.mListItemName = (TextView) convertView.findViewById(R.id.text_view_name);
      viewHolder.mListItemDescription = (TextView) convertView.findViewById(R.id.text_view_description);
      convertView.setTag(viewHolder);
      } else {
      viewHolder = (ViewHolder) convertView.getTag();
      }

       Picasso.with(getContext()).load((Integer) mData.get(position).get(KEY_AVATAR))
               .resize(EuclidActivity.sScreenWidth, EuclidActivity.sProfileImageHeight).centerCrop()
               .placeholder(R.color.blue)
               .into(viewHolder.mListItemAvatar);
      
       viewHolder.mListItemName.setText(mData.get(position).get(KEY_NAME).toString().toUpperCase());
       viewHolder.mListItemDescription.setText((String) mData.get(position).get(KEY_DESCRIPTION_SHORT));
       viewHolder.mViewOverlay.setBackground(EuclidActivity.sOverlayShape);
      
       return convertView;
      

      }

      static class ViewHolder {
      View mViewOverlay;
      ImageView mListItemAvatar;
      TextView mListItemName;
      TextView mListItemDescription;
      }
      }

  • 相关阅读:
    Repeater 双向排序
    将具有固定格式的text 类型中的数据分离出来的一种方法
    ASP.NET 快速构建应用程序页面主框架
    2分分页处理存储过程通用存储过程
    C#3.0之匿名类型
    常用的js收集
    用CSS实现DataGird滚动而表头不动
    Lucene.Net 创建索引和检索
    Lucene.net 实现全文搜索
    SQL 中操作日期的几个函数
  • 原文地址:https://www.cnblogs.com/2506236179zhw/p/14926427.html
Copyright © 2011-2022 走看看