android仿iphone主题效果的主菜单

现在很多第三方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 /* <span style="font-size:14px;">圆角半径 </span>*/) {
  return getRoundCornerDrawable(ctx,
    mContext.getResources().getDrawable(resId), roundPX);
 } 

 private Drawable getRoundCornerDrawable(Context ctx, Drawable drawable,
   float roundPX /* <span style="font-size:14px;">圆角半径 </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, 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);
 }
}

源码下载:android仿iphone主题之主菜单

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 基于Android实现点击某个按钮让菜单选项从按钮周围指定位置弹出

    Android Material Design:PopupMenu Android Material Design 引入的PopupMenu类似过去的上下文菜单,但是更灵活. 如图所示: 现在给出实现上图PopupMenu的代码. 本例是一个普通的Button触发弹出PopupMenu. 测试的MainActivity.java : package zhangphil.materialdesign; import android.app.Activity; import android.os.B

  • Android仿QQ空间底部菜单示例代码

    之前曾经在网上看到Android仿QQ空间底部菜单的Demo,发现这个Demo有很多Bug,布局用了很多神秘数字.于是研究了一下QQ空间底部菜单的实现,自己写了一个,供大家参考.效果如下图所示:   1.实现原理很简单,底部菜单是一个水平分布的LinearLayout,里面又是五个LinearLayout,它们的layout_weight都为1,意味着底部菜单的子控件将屏幕宽度平均分为5部分.五个LinearLayout除了中间那个,其余都在里面放置ImageView和TextView(中间先空

  • Android界面设计(APP设计趋势 左侧隐藏菜单右边显示content)

    相关文章android popwindow实现左侧弹出菜单层http://www.jb51.net/article/33533.htm 移动App设计的13大精髓http://www.jb51.net/article/33534.htm 这文章讲述了2013年未来的移动APP设计趋势,感觉挺有道理的.wp8的平面界面设计已经取得很大的成功,很多应用也都是采取相同的设计如zaker,还有类似本文要展示的左侧导航菜单右边显示主要内容的设计,通过menu菜单或者左右拖动可以弹出左侧导航菜单,国内的应用

  • android popwindow实现左侧弹出菜单层及PopupWindow主要方法介绍

    PopupWindow可以实现浮层效果,主要方法有:可以自定义view,通过LayoutInflator方法:可以出现和退出时显示动画:可以指定显示位置等. 为了将PopupWindow的多个功能展现并力求用简单的代码实现,编写了一个点击按钮左侧弹出菜单的功能,实现出现和退出时显示动画效果并点击其他区域时弹出层自动消失,效果图如下: 源码: 1.PopwindowOnLeftActivity.java 复制代码 代码如下: package com.pop.main; import android

  • Android之用PopupWindow实现弹出菜单的方法详解

    在使用UC-WebBrowser时,你会发现它的弹出菜单跟系统自带的菜单不一样.它实现更多菜单选项的显示和分栏.其实,它的本身是PopupWindow或者是AlertDialog对话框,在里面添加两个GridView控件,一个是菜单标题栏,一个是菜单选项.菜单选项视图的切换可以通过适配器的变换,轻松地实现.点击下载该实例:一.运行截图:           二.实现要点:(1)屏蔽系统弹出的菜单:1.首先创建至少一个系统的菜单选项 复制代码 代码如下: @Override public bool

  • Android左右滑出菜单实例分析

    现在的Android应用,只要有一个什么新的创意,过不了多久,几乎所有的应用都带这个创意.这不,咱们公司最近的一个持续性的项目,想在首页加个从左滑动出来的菜单,我查阅网上资料,并自己摸索,实现了左.右两边都能滑出菜单,并且,左.右菜单中,都可以加ListView等这类需要解决GestureDetector冲突的问题(如在首页面中,含有ListView,上下滚动时,左右不动,相反,左右滑动菜单时,上下不动,听着头就大了吧!) 先上几张图,给大家瞧瞧,对整体有个了解:  一.首页布局: 复制代码 代

  • Android ListView长按弹出菜单二种实现方式示例

    复制代码 代码如下: /** * 知识点1:ListView item:两种长按弹出菜单方式* 知识点2:ListView SimpleAdapter的使用* 知识点 3:在java代码中创建一个ListView*/ public class ListOnLongClickActivity extends Activity {         private LinearLayout myListViewlayout;         private ListView mListView;   

  • Android开发技巧之我的菜单我做主(自定义菜单)

    Android SDK本身提供了一种默认创建菜单的机制.但通过这种机制创建的菜单虽然从功能上很完备,但在界面效果上实在是有点"土".对于一个拥有绚丽界面的程序配上一个有点"土"的菜单,会使用户感觉很怪,甚至会使绚丽的界面大打折扣.实际上,对于如此灵活和强大的Android系统,修改菜单的样式只是小菜一碟.为程序加入漂亮菜单的方法很多.在本节先介绍一种比较常用的方法,就是通过onKeyDown事件方法和PopupWindow实现自定义的菜单.至于通过这种技术能否设计出

  • android底部菜单栏实现原理与代码

    上一个项目已经做完了,这周基本上没事,所以整理了下以前的项目,想把一些通用的部分封装起来,这样以后遇到相似的项目就不用重复发明轮子了,也节省了开发效率.今天把demo贴出来一是方便以后自己查询,二是希望同时也能帮到大家. 底部菜单栏很重要,我看了一下很多应用软件都是用了底部菜单栏做.我这里使用了tabhost做了一种通用的(就是可以像微信那样显示未读消息数量的,虽然之前也做过但是layout下的xml写的太臃肿,这里去掉了很多不必要的层,个人看起来还是不错的,所以贴出来方便以后使用). 先看一下

  • Android实现原生侧滑菜单的超简单方式

    先来看看效果图 当你点击菜单可以更改图标,例如点击happy,首页就会变一个笑脸,这个实现的过程超级简单 你需要使用ToolBar与DrawableLayout两个比较新的控件 首先要写三个xml布局文件,我这里的布局文件是使用了include标签嵌入的,代码如下 headbar_toolbar.xml <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar

随机推荐