嗯,首先自我介绍一下,本人目前在校学生,安卓开发小菜一个,这是我的第一篇博客,希望能以这篇博客为起点,纪录自己的成长,也与各位安卓新手共勉。
进入正题,秉着无图无jb的观点,先上个效果图给各位看官看下,有兴趣的继续看,没兴趣的请便,o(^▽^)o。
总体模仿的还是挺像的,个人认为。
1.对布局的旋转、透明度等的处理
2.自定义各种形状的图片(例如圆形图片)
3.图片的高斯模糊
4.动画处理
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:id="@+id/rlRoot" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" tools:context="com.chenantoa.main.MainActivity"> <FrameLayout android:id="@+id/flContainer" android:layout_width="match_parent" android:paddingTop="10dp" android:paddingBottom="20dp" android:layout_height="match_parent" android:layout_centerInParent="true"> <ImageView android:layout_gravity="center_horizontal" android:src="@drawable/bg" android:layout_width="350dp" android:layout_height="480dp"/> </FrameLayout> </RelativeLayout>
很简单,没什么好说的,一个FrameLayout,这是一个布局,用来陈放item的,里面的ImageView是个什么东西呢?是一个背景图片,也就是刚才上面所说的类似几张纸叠起来的效果,有人可能会问为什么不直接在FrameLayout写个backgroud呢?我一开始也是这么做的,那么我必须把FrameLayout的大小定义成容器的大小,也就是不能写成match_parent了,这里就出问题了。当容器里面的item旋转的时候,超过容器的那部分将不会显示。
不过我自己实验过,如果一开始就在FrameLayout声明好item,而不是动态添加的话,就算移动出了容器的范围,也能够显示,不知道为什么,有知道的大神可以在下面留言,谢谢。
<?xml version="1.0" encoding="utf-8"?> <FrameLayout android:id="@+id/llItem" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="350dp" android:layout_height="500dp"> <LinearLayout android:layout_width="350dp" android:layout_height="500dp" android:background="@drawable/item_bg" android:gravity="center_horizontal" android:orientation="vertical"> <FrameLayout android:id="@+id/flAvater" android:layout_width="match_parent" android:layout_height="140dp"> <com.chenantao.view.widget.MultipleShapeImg android:id="@+id/blurAvatar" android:layout_width="match_parent" android:layout_height="130dp" android:src="@mipmap/avatar" app:type="arcRectangle"/> <com.chenantao.view.widget.MultipleShapeImg android:id="@+id/roundAvatar" android:layout_width="75dp" android:layout_height="75dp" android:layout_gravity="center|bottom" android:src="@mipmap/avatar" app:type="round"/> <TextView android:id="@+id/tvUsername" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="10dp" android:textColor="@android:color/white" android:textSize="20sp"/> </FrameLayout> <TextView android:id="@+id/tvSchool" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="some message" android:textColor="@android:color/black" android:textSize="15sp"/> <TextView android:id="@+id/tvMajor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="some message" android:textSize="15sp"/> <View android:layout_width="300dp" android:layout_height="1px" android:layout_gravity="center_horizontal" android:layout_marginTop="25dp" android:background="@android:color/darker_gray"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:gravity="center" android:orientation="horizontal"> <TextView android:id="@+id/tvEntranceTime" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="2013级入学" android:textSize="15sp"/> <View android:layout_width="1dp" android:layout_height="23dp" android:layout_marginLeft="10dp" android:layout_marginRight="40dp" android:layout_marginTop="3dp" android:background="@android:color/darker_gray"/> <TextView android:id="@+id/tvAdress" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="广州" android:textSize="15sp"/> </LinearLayout> <View android:layout_width="300dp" android:layout_height="1px" android:layout_gravity="center_horizontal" android:layout_marginTop="25dp" android:background="@android:color/darker_gray"/> <TextView android:id="@+id/tvSkill" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="some message" android:textSize="15sp"/> </LinearLayout> <ImageView android:id="@+id/ivIgnore" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center" android:src="@mipmap/ignore" android:visibility="gone"/> <ImageView android:id="@+id/ivInterested" android:layout_width="200dp" android:layout_height="200dp" android:layout_gravity="center" android:src="@mipmap/interested" android:visibility="gone"/> </FrameLayout>
private FrameLayout mContainer;//framelayout容器 private float mRotateFactor;//控制item旋转范围 private double mItemAlphaFactor;//控制item透明度变化范围 private double mItemIvAlphaFactor;//控制item上面的图片的透明度变化范围 private float mLimitTranslateX = 100;//限制移动距离,当超过这个距离的时候,删除该item private List<User> mDatas;//item的数据 private int mIndex = -1;//标识当前读取到数据的第几个下标
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mDatas = GenerateData.getDatas(); //从屏幕的最右边滑动到最左边,最多旋转60度 int screenWidth = ScreenUtils.getScreenWidth(this); mRotateFactor = 60 * 1.0f / screenWidth; //左滑,透明度最少到0.3f mItemAlphaFactor = 0.7 * 1.0f / screenWidth / 2; //item上面图标透明度的变化,滑动4分之一屏幕的距离便使其完全显示 mItemIvAlphaFactor = 4.0f / screenWidth; mContainer = (FrameLayout) findViewById(R.id.flContainer); }
public void addViewToBehind() { if (mIndex == mDatas.size() - 1) { return; } //加载布局 final View item = LayoutInflater.from(this).inflate(R.layout.stack_item, null); FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(dp2px(350), dp2px(470), Gravity .CENTER_HORIZONTAL); item.setLayoutParams(lp); mContainer.addView(item, 1); //初始化item的数据 User user = mDatas.get(++mIndex);//取出一条数据,并且增加index的下标 ImageView roundAvatar = (ImageView) item.findViewById(R.id.roundAvatar); ImageView blurAvatar = (ImageView) item.findViewById(R.id.blurAvatar); // Log.e("cat", "avatar resId:" + user.getAvater()); CatImageLoader.getInstance().loadImage(user.getAvater(), blurAvatar); CatImageLoader.getInstance().loadImage(user.getAvater(), roundAvatar); TextView tvUsername = (TextView) item.findViewById(R.id.tvUsername); TextView tvSchool = (TextView) item.findViewById(R.id.tvSchool); TextView tvMajor = (TextView) item.findViewById(R.id.tvMajor); TextView tvEntranceTime = (TextView) item.findViewById(R.id.tvEntranceTime); TextView tvSkill = (TextView) item.findViewById(R.id.tvSkill); final ImageView ivIgnore = (ImageView) item.findViewById(R.id.ivIgnore); final ImageView ivInterested = (ImageView) item.findViewById(R.id.ivInterested); tvUsername.setText(user.getName()); tvSchool.setText(user.getSchool()); tvMajor.setText(user.getMajor() + " | " + user.getSchoolLevel()); tvEntranceTime.setText(user.getEntranceTime()); tvSkill.setText("装逼 吹牛逼"); //设置item的重心,主要是旋转的中心 item.setPivotX(item.getLayoutParams().width / 2); item.setPivotY(item.getLayoutParams().height * 2); item.setOnTouchListener(new View.OnTouchListener() { float touchX, distanceX; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: touchX = event.getRawX(); break; case MotionEvent.ACTION_MOVE: distanceX = event.getRawX() - touchX; item.setRotation(distanceX * mRotateFactor); //alpha scale 1~0.3 //item的透明度为从1到0.3 item.setAlpha(1 - (float) Math.abs(mItemAlphaFactor * distanceX)); if (distanceX < 0)//如果为左滑 { //显示忽略图标,隐藏感兴趣图标 ivIgnore.setVisibility(View.VISIBLE); ivInterested.setVisibility(View.GONE); ivIgnore.setAlpha((float) (Math.abs(distanceX) * mItemIvAlphaFactor)); } else { //显示感兴趣图标,隐藏忽略图标 ivIgnore.setVisibility(View.GONE); ivInterested.setVisibility(View.VISIBLE); ivInterested.setAlpha((float) (distanceX * mItemIvAlphaFactor)); } break; case MotionEvent.ACTION_UP: if (Math.abs(distanceX) > mLimitTranslateX) { View removeView = mContainer.getChildAt(mContainer.getChildCount() - 1); removeView(removeView, distanceX < 0 ? true : false); addViewToBehind(); } else { //复位 item.setRotation(0); item.setAlpha(1); ivIgnore.setAlpha(1.0f); ivInterested.setAlpha(1.0f); ivIgnore.setVisibility(View.GONE); ivInterested.setVisibility(View.GONE); } break; } return true; } }); }
public void removeView(final View view, boolean left) { view.animate() .alpha(0) .rotation(left ? -90 : 90) .setDuration(300).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { mContainer.removeView(view); if (mContainer.getChildCount() == 2)//如果只剩一条item和背景图片 { //隐藏背景图片 mContainer.getChildAt(0).setVisibility(View.GONE); } else if ((mContainer.getChildCount() == 1)) { Toast.makeText(MainActivity.this, "已是最后一页...", Toast.LENGTH_SHORT).show(); } } }); }
matrix = new Matrix(); bitmapShader = new BitmapShader(src, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); matrix.setScale(scale, scale); bitmapShader.setLocalMatrix(matrix); paint.setShader(bitmapShader);
Path path = new Path(); //贝塞尔曲线的操作点x y int deviation = 50;//圆弧突起的高度 int controlY = getMeasuredHeight() + deviation; int controlX = getMeasuredWidth() / 2; path.moveTo(0, 0); path.lineTo(getMeasuredWidth(), 0); path.lineTo(getMeasuredWidth(), getMeasuredHeight() - deviation); path.quadTo(controlX, controlY, 0, getMeasuredHeight() - deviation); path.close(); canvas.drawPath(path, paint);
public static Bitmap blur(Bitmap src, View view) { float scaleFactor = 8; float radius = 5; Bitmap overlay = Bitmap.createBitmap( (int) (view.getMeasuredWidth() / scaleFactor), (int) (view.getMeasuredHeight() / scaleFactor), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(overlay); canvas.translate(-view.getLeft() / scaleFactor, view.getTop() / scaleFactor); canvas.scale(1 / scaleFactor, 1 / scaleFactor); Paint paint = new Paint(); paint.setFlags(Paint.FILTER_BITMAP_FLAG); canvas.drawBitmap(src, 0, 0, paint); overlay = FastBlur.doBlur(overlay, (int) radius, true); return overlay; }
核心代码都已经贴完了,想看完整的可以通过我下面的链接down下来运行一下,最好是用AndroidStudio,比较方便,用eclipse的话就自己把代码复制过去吧,还有记得资源,都帮你们准备好拉。这效果你们满意了吗?显然没有,有点编程基础的肯定都能看出来,嗯,耦合性太高了,过几天有空我将抽取出一个单独的自定义布局来实现这种效果,以便有更好的复用性。
终于写完了我的第一篇博客,写的可能会有哪里表达的不好,各位前辈或者同辈有什么可以教我的都可以在下面留言哦。
下篇博客点击打开链接