现在很多第三方Launcher((如360Launcher,GoLauncher)带有iphone主题,相信玩Android的人大都知道。

本例实现仿iphone主题的launcher的冰山一角。如下图:

从效果看,大概就能猜出用什么控件类(支持左右滑动的控件类+GridView),支持左右滑动的控件类,有很多了比如常用的Gallery,ViewPager,ViewFlipper,ViewFlow等等,本例自定义继承ViewGroup的。看过launcher源码的人应该都知道 有个Workspace类继承ViewGroup实现主菜单的。

闲话不多说了

布局:main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="fill_parent"    android:layout_height="fill_parent"    android:orientation="vertical" >    <com.xyz.workspace.Workspace        android:id="@+id/workspace"        android:layout_width="fill_parent"        android:layout_height="fill_parent" />    <com.xyz.workspace.PageIndicator        android:id="@+id/indicator"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_centerHorizontal="true"        android:layout_marginBottom="20dip" /></RelativeLayout>

第一个自定义类Workspace就是实现左右滑动的,第二个类PageIndicator做指示器用。

Workspace.java

package com.xyz.workspace;import java.util.List;import android.content.Context;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.widget.Scroller;public class Workspace extends ViewGroup {    private static final String TAG = "Workspace";    private Scroller mScroller;    private VelocityTracker mVelocityTracker;    private static final int DEFAULT_SCREEN = 0;    private static final int TOUCH_STATE_REST = 0;    private static final int TOUCH_STATE_SCROLLING = 1;    private static final int SNAP_VELOCITY = 600;    public static final int APP_PAGE_SIZE = 16;    private int mCurScreen;    private int mTouchState = TOUCH_STATE_REST;    private int mTouchSlop;    private float mLastMotionX;    private float mLastMotionY;    private OnViewChangedListener mOnViewChangedListener;    public Workspace(Context context, AttributeSet attrs) {        this(context, attrs, 0);        // TODO Auto-generated constructor stub    }    public Workspace(Context context, AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);        // TODO Auto-generated constructor stub        mScroller = new Scroller(context);        mCurScreen = DEFAULT_SCREEN;        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();    }    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        // TODO Auto-generated method stub        if (changed) {            int childLeft = 0;            final int childCount = getChildCount();            for (int i = 0; i < childCount; i++) {                final View childView = getChildAt(i);                if (childView.getVisibility() != View.GONE) {                    final int childWidth = childView.getMeasuredWidth();                    childView.layout(childLeft, 0, childLeft + childWidth,                            childView.getMeasuredHeight());                    childLeft += childWidth;                }            }        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        final int width = MeasureSpec.getSize(widthMeasureSpec);        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);        if (widthMode != MeasureSpec.EXACTLY) {            throw new IllegalStateException(                    "ScrollLayout only canmCurScreen run at EXACTLY mode!");        }        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);        if (heightMode != MeasureSpec.EXACTLY) {            throw new IllegalStateException(                    "ScrollLayout only can run at EXACTLY mode!");        }        final int count = getChildCount();        for (int i = 0; i < count; i++) {            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);        }        scrollTo(mCurScreen * width, 0);    }    public void snapToDestination() {        final int screenWidth = getWidth();        final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;        snapToScreen(destScreen);    }    public void snapToScreen(int whichScreen) {        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));        if (getScrollX() != (whichScreen * getWidth())) {            final int delta = whichScreen * getWidth() - getScrollX();            mScroller.startScroll(getScrollX(), 0, delta, 0,                    Math.abs(delta) * 2);            mCurScreen = whichScreen;            invalidate();        }        if (mOnViewChangedListener != null) {            mOnViewChangedListener.onChange(getChildCount(), whichScreen);        }    }    public void setToScreen(int whichScreen) {        whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));        mCurScreen = whichScreen;        scrollTo(whichScreen * getWidth(), 0);    }    public int getCurScreen() {        return mCurScreen;    }    @Override    public void computeScroll() {        // TODO Auto-generated method stub        if (mScroller.computeScrollOffset()) {            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());            postInvalidate();        }    }    @Override    public boolean onTouchEvent(MotionEvent event) {        // TODO Auto-generated method stub        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(event);        final int action = event.getAction();        final float x = event.getX();        final float y = event.getY();        switch (action) {        case MotionEvent.ACTION_DOWN:            if (!mScroller.isFinished()) {                mScroller.abortAnimation();            }            mLastMotionX = x;            break;        case MotionEvent.ACTION_MOVE:            int deltaX = (int) (mLastMotionX - x);            mLastMotionX = x;            scrollBy(deltaX, 0);            break;        case MotionEvent.ACTION_UP:            final VelocityTracker velocityTracker = mVelocityTracker;            velocityTracker.computeCurrentVelocity(1000);            int velocityX = (int) velocityTracker.getXVelocity();            if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {                snapToScreen(mCurScreen - 1);            } else if (velocityX < -SNAP_VELOCITY                    && mCurScreen < getChildCount() - 1) {                snapToScreen(mCurScreen + 1);            } else {                snapToDestination();            }            if (mVelocityTracker != null) {                mVelocityTracker.recycle();                mVelocityTracker = null;            }            mTouchState = TOUCH_STATE_REST;            break;        case MotionEvent.ACTION_CANCEL:            mTouchState = TOUCH_STATE_REST;            break;        }        return true;    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        // TODO Auto-generated method stub        final int action = ev.getAction();        if ((action == MotionEvent.ACTION_MOVE)                && (mTouchState != TOUCH_STATE_REST)) {            return true;        }        final float x = ev.getX();        final float y = ev.getY();        switch (action) {        case MotionEvent.ACTION_MOVE:            final int xDiff = (int) Math.abs(mLastMotionX - x);            if (xDiff > mTouchSlop) {                mTouchState = TOUCH_STATE_SCROLLING;            }            break;        case MotionEvent.ACTION_DOWN:            mLastMotionX = x;            mLastMotionY = y;            mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST                    : TOUCH_STATE_SCROLLING;            break;        case MotionEvent.ACTION_CANCEL:        case MotionEvent.ACTION_UP:            mTouchState = TOUCH_STATE_REST;            break;        }        return mTouchState != TOUCH_STATE_REST;    }    public void setOnViewChangedListener(OnViewChangedListener l) {        mOnViewChangedListener = l;    }    public interface OnViewChangedListener {        public void onChange(int cnt, int index);    }}

PageIndicator.java:
package com.xyz.workspace;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.widget.ImageView;import android.widget.LinearLayout;public class PageIndicator extends LinearLayout {    private Context mContext;    public PageIndicator(Context ctx) {        super(ctx);        // TODO Auto-generated constructor stub        mContext = ctx;    }    public PageIndicator(Context ctx, AttributeSet attrs) {        super(ctx, attrs);        // TODO Auto-generated constructor stub        mContext = ctx;    }    public void setIndication(int cnt, int index) {        if (index < 0 || index > cnt)             index = 0;        removeAllViews();        for (int i = 0; i < cnt; i++) {            ImageView iv = new ImageView(mContext);            iv.setImageResource(index == i ? R.drawable.indicator_current                    : R.drawable.indicator);            if (i != 0 || i != cnt - 1) {                iv.setPadding(4, 0, 4, 0);            }            addView(iv);        }    }}
这两个 类的作用上面已经说了,有什么看不明白的欢迎提问,或自行google。

ViewGroup实现好了,剩下就是实现GridView显示系统所有app,主要工作也就是实现GridView的适配器---GridAdapter

package com.xyz.workspace;import java.util.List;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.pm.ResolveInfo;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.BaseAdapter;import static com.xyz.workspace.Workspace.APP_PAGE_SIZE;public class GridAdapter extends BaseAdapter implements OnClickListener {    private Context mContext;    private int mPageIndex;    private List<ResolveInfo> mPackagesInfo;    public GridAdapter(Context context, List<ResolveInfo> listInfo, int page) {        mContext = context;        mPackagesInfo = listInfo;        mPageIndex = page;    }    @Override    public int getCount() {        // TODO Auto-generated method stub        int size = mPackagesInfo.size();        return size / APP_PAGE_SIZE > 0                && size - (APP_PAGE_SIZE * (mPageIndex + 1)) > 0 ? APP_PAGE_SIZE                : size % APP_PAGE_SIZE;    }    @Override    public Object getItem(int position) {        // TODO Auto-generated method stub        return mPackagesInfo.get(APP_PAGE_SIZE * mPageIndex + position);    }    @Override    public long getItemId(int position) {        // TODO Auto-generated method stub        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        // TODO Auto-generated method stub        if (convertView == null) {            convertView = new AppItem(mContext, (ResolveInfo) getItem(position));        }        convertView.setOnClickListener(this);        convertView.setTag(Integer.valueOf(position));        return convertView;    }    /** 点击启动app **/    @Override    public void onClick(View v) {        // TODO Auto-generated method stub        int pos = (Integer) v.getTag();        ResolveInfo info = (ResolveInfo) getItem(pos);        Intent i = new Intent(Intent.ACTION_MAIN);        i.addCategory(Intent.CATEGORY_LAUNCHER);        i.setComponent(new ComponentName(info.activityInfo.packageName,                info.activityInfo.name));        mContext.startActivity(i);    }}

GridView的每个item不用说,一看就知道是一个LinearLayout上面是个ImageView,下面一个TextView了。我把它封装了下---AppItem:

package com.xyz.workspace;import android.content.Context;import android.content.pm.PackageManager;import android.content.pm.ResolveInfo;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.PixelFormat;import android.graphics.PorterDuffXfermode;import android.graphics.Rect;import android.graphics.RectF;import android.graphics.Bitmap.Config;import android.graphics.PorterDuff.Mode;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.view.LayoutInflater;import android.widget.ImageView;import android.widget.RelativeLayout;import android.widget.TextView;public class AppItem extends RelativeLayout {    private Context mContext;    private ImageView mAppIcon;    private TextView mAppName;    private ResolveInfo mAppInfo;    private PackageManager mPackageManager;    public AppItem(Context context) {        super(context);        mContext = context;        mPackageManager = context.getPackageManager();        LayoutInflater.from(context).inflate(R.layout.app_item, this);        mAppIcon = (ImageView) findViewById(R.id.icon);        mAppName = (TextView) findViewById(R.id.app_name);    }    public AppItem(Context context, ResolveInfo info) {        this(context);        mAppInfo = info;        show();    }    private void show() {        String packageName = mAppInfo.activityInfo.packageName;        String appName = mAppInfo.activityInfo.loadLabel(mPackageManager)                .toString();        if (appName.equals("拨号")) {            mAppIcon.setImageResource(R.drawable.com_android_phone);        } else if (packageName.equals("com.android.contacts")) {            mAppIcon.setImageResource(R.drawable.com_android_contacts);        } else if (packageName.equals("com.android.mms")) {            mAppIcon.setImageResource(R.drawable.com_android_mms);        } else if (packageName.equals("com.android.music")) {            mAppIcon.setImageResource(R.drawable.com_android_music);        } else if (packageName.equals("com.android.browser")) {            mAppIcon.setImageResource(R.drawable.com_android_browser);        } else if (packageName.equals("com.android.settings")) {            mAppIcon.setImageResource(R.drawable.com_android_settings);        } else if (packageName.equals("com.android.email")) {            mAppIcon.setImageResource(R.drawable.com_android_email);        } else if (packageName.equals("com.android.calendar")) {            mAppIcon.setImageResource(R.drawable.com_android_calendar);        } else if (packageName.equals("com.android.calculator2")) {            mAppIcon.setImageResource(R.drawable.com_android_calculator2);        } else if (packageName.equals("com.android.deskclock")) {            mAppIcon.setImageResource(R.drawable.com_android_deskclock);        } else if (packageName.equals("com.android.camera")) {            mAppIcon.setImageResource(R.drawable.com_android_camera);        } else if (packageName.equals("com.android.soundrecorder")) {            mAppIcon.setImageResource(R.drawable.com_android_soundrecorder);        } else if (packageName.equals("com.tencent.mobileqq")) {            mAppIcon.setImageResource(R.drawable.com_tencent_qq);        } else if (packageName.equals("com.tencent.mm")) {            mAppIcon.setImageResource(R.drawable.com_tencent_mm);        } else if (packageName.equals("com.tencent.mtt")) {            mAppIcon.setImageResource(R.drawable.com_tencent_mtt);        } else if (packageName.equals("com.sina.weibo")) {            mAppIcon.setImageResource(R.drawable.com_sina_weibo);        } else if (packageName.equals("com.sds.android.ttpod")) {            mAppIcon.setImageResource(R.drawable.com_sds_android_ttpod);            // ////////////////////////////////////////////////////////////////        } else if (packageName.equals("com.youdao.dict")) {            mAppIcon.setImageResource(R.drawable.com_youdao_dict);        } else {            mAppIcon.setImageDrawable(getRoundCornerDrawable(mContext,                    mAppInfo.activityInfo.loadIcon(mPackageManager), 20));        }        mAppName.setText(appName);    }    private Drawable getRoundCornerDrawable(Context ctx, int resId,            float roundPX /* 圆角半径 */) {        return getRoundCornerDrawable(ctx,                mContext.getResources().getDrawable(resId), roundPX);    }    private Drawable getRoundCornerDrawable(Context ctx, Drawable drawable,            float roundPX /* 圆角半径 */) {        int w = ctx.getResources()                .getDimensionPixelSize(R.dimen.app_icon_width);        int h = w;        Bitmap bitmap = Bitmap                .createBitmap(                        w,                        h,                        drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888                                : Bitmap.Config.RGB_565);        Canvas canvas = new Canvas(bitmap);        drawable.setBounds(0, 0, w, h);        drawable.draw(canvas);        int width = bitmap.getWidth();        int height = bitmap.getHeight();        Bitmap retBmp = Bitmap.createBitmap(width, height, Config.ARGB_8888);        Canvas can = new Canvas(retBmp);        final int color = 0xff424242;        final Paint paint = new Paint();        final Rect rect = new Rect(0, 0, width, height);        final RectF rectF = new RectF(rect);        paint.setColor(color);        paint.setAntiAlias(true);        can.drawARGB(0, 0, 0, 0);        can.drawRoundRect(rectF, roundPX, roundPX, paint);        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));        can.drawBitmap(bitmap, rect, rect, paint);        return new BitmapDrawable(retBmp);    }}
注意咯,show函数就是替换显示对应iphone里app的图标(来源反编译iphone主题的launcher或锁屏),利用 包名 判断是哪个应用再换上对应图标,例如com.android.mms---信息com.android.contacts---联系人,这里有疑问,为什么phone模块的package_name的也是com.android.contacts有人知道么?谢谢啦!

AppItem引用一个布局:

app_item.xml:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="@dimen/app_icon_width"    android:layout_height="@dimen/app_icon_height"    android:gravity="center"    android:orientation="vertical" >    <ImageView        android:id="@+id/icon"        android:layout_width="@dimen/app_icon_width"        android:layout_height="@dimen/app_icon_width"        android:layout_gravity="center_horizontal" />    <TextView        android:id="@+id/app_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_gravity="center_horizontal"        android:ellipsize="marquee"        android:maxWidth="@dimen/app_icon_height"        android:singleLine="true"        android:textColor="@android:color/white"        android:textSize="12sp" /></LinearLayout>
主Activity就是获取所有app信息及初始化界面,

MainActivty.java:

package com.xyz.workspace;import java.util.List;import com.xyz.workspace.Workspace.OnViewChangedListener;import android.app.Activity;import android.content.Intent;import android.content.pm.ResolveInfo;import android.os.Bundle;import android.view.Gravity;import android.widget.GridView;import static com.xyz.workspace.Workspace.APP_PAGE_SIZE;public class MainActivity extends Activity implements OnViewChangedListener {    private Workspace mWorkspace;    private PageIndicator mIndicator;    /** Called when the activity is first created. */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        mWorkspace = (Workspace) findViewById(R.id.workspace);        mIndicator = (PageIndicator) findViewById(R.id.indicator);        List<ResolveInfo> apps = loadApps();        for (int i = 0; i < Math.ceil(1.0f * apps.size() / APP_PAGE_SIZE); i++) {            GridView grid = new GridView(this);            grid.setNumColumns(4);            grid.setHorizontalSpacing(10);            grid.setVerticalSpacing(40);            grid.setPadding(30, 50, 30, 20);            grid.setGravity(Gravity.CENTER);            grid.setAdapter(new GridAdapter(this, apps, i));            mWorkspace.addView(grid);        }        mWorkspace.setOnViewChangedListener(this);        mIndicator.setIndication(mWorkspace.getChildCount(), 0);    }    private List<ResolveInfo> loadApps() {        Intent i = new Intent(Intent.ACTION_MAIN, null);        i.addCategory(Intent.CATEGORY_LAUNCHER);        return getPackageManager().queryIntentActivities(i, 0);    }    @Override    public void onChange(int cnt, int index) {        // TODO Auto-generated method stub        mIndicator.setIndication(cnt, index);    }}
下载地址:http://download.csdn.net/detail/zhouyuanjing/5047826

就这么多了,~~完~~

更多相关文章

  1. Android滑动组件----RecyclerView并且实现点击事件(2)
  2. Android仿微博、人人Feed详情页吸附导航栏
  3. android 软件盘相关
  4. android 自动查找控件id
  5. android —— 自定义控件 利用 ViewPage 实现滑动屏
  6. Android(安卓)Banner轮播控件
  7. MeasureSpec之详细分析
  8. Android基础入门教程——8.1.3 Android中的13种Drawable小结 Par
  9. Android:SlidingMenu+ListView+ViewPager 的滑动冲突

随机推荐

  1. How to tile a background image in Andr
  2. android sqlite应用
  3. Android聊天软件开发(基于网易云IM即时通
  4. Android机顶盒 获取当前连接网络的Ip地址
  5. android 如何判断程序是否在前台运行
  6. Android播放循环播放本地图片
  7. Android(安卓)键盘弹出与隐藏
  8. Android仿iOS时间选择器
  9. Android(安卓)摄像头聚焦
  10. Android: annoying exception Unable to