现在很多第三方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,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,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(),delta,Math.abs(delta) * 2); mCurScreen = whichScreen; invalIDate(); } if (mOnVIEwChangedListener != null) { mOnVIEwChangedListener.onChange(getChildCount(),whichScreen); } } public voID setToScreen(int whichScreen) { whichScreen = Math.max(0,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,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 /* <span >圆角半径 </span>*/) { return getRoundCornerDrawable(ctx,mContext.getResources().getDrawable(resID),roundPX); } private Drawable getRoundCornerDrawable(Context ctx,Drawable drawable,float roundPX /* <span >圆角半径 </span>*/) { 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,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,wIDth,height); final RectF rectF = new RectF(rect); paint.setcolor(color); paint.setAntiAlias(true); can.drawARGB(0,0); can.drawRoundRect(rectF,roundPX,paint); paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN)); can.drawBitmap(bitmap,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); } }
源码下载:android仿iphone主题之主菜单
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的android仿iphone主题效果的主菜单全部内容,希望文章能够帮你解决android仿iphone主题效果的主菜单所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)