人人客户端向右滑出式菜单:
试着实现了一个,先上效果图:
下面简单说明一下实现原理:
有两个activity,MainActivity和SettingActivity,实现这个效果两个步骤:
1、点击MainActivity左上角的按钮,MainActivity先切换到SettingActivity,获得MainActivity的布局快照,即一张代表其布局的bitmap
2、SettingActivity采用绝对布局,最上面先是覆盖了一张透明的imageView,接着将这个imageview填充上上一步的布局快照,然后通过位移动画移动这张imageView,给人的感觉就好像是前一个activity在移动。
待改进:加入手势控制。
希望大家提出更好的实现方法。
上代码:有注释
MainActivity.java
import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.Toast; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample); findViewById(R.id.sample_button).setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { SettingActivity.prepare(MainActivity.this, R.id.inner_content); startActivity(new Intent(MainActivity.this, SettingActivity.class)); overridePendingTransition(0, 0); } }); } }SettingActivity.java
import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.os.Bundle; import android.util.TypedValue; import android.view.KeyEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.TranslateAnimation; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.widget.RelativeLayout.LayoutParams; public class SettingActivity extends Activity { private ImageView mCover; private ListView mList; private Animation mStartAnimation; private Animation mStopAnimation; private static final int DURATION_MS = 400; private static Bitmap sCoverBitmap = null; // 2个步骤 // 1. activity-->other activity // 2. anim // 先切换到另一个activity // 再获得之前activity屏幕的快照将它作为一个cover覆盖在下一个屏幕的上面,然后通过动画移动这个cover,让人感觉好像是前一个屏幕的移动。 public static void prepare(Activity activity, int id) { if (sCoverBitmap != null) { sCoverBitmap.recycle(); } // 用指定大小生成一张透明的32位位图,并用它构建一张canvas画布 sCoverBitmap = Bitmap.createBitmap( activity.findViewById(id).getWidth(), activity.findViewById(id) .getHeight(), Config.ARGB_8888); Canvas canvas = new Canvas(sCoverBitmap); // 将指定的view包括其子view渲染到这种画布上,在这就是上一个activity布局的一个快照,现在这个bitmap上就是上一个activity的快照 activity.findViewById(id).draw(canvas); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // 绝对布局最上层覆盖了一个imageview setContentView(R.layout.main); initAnim(); mCover = (ImageView) findViewById(R.id.slidedout_cover); mCover.setImageBitmap(sCoverBitmap); mCover.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { close(); } }); mList = (ListView) findViewById(R.id.list); mList.setAdapter(new ArrayAdapter<String>(SettingActivity.this, android.R.layout.simple_list_item_1, new String[] { " First", " Second", " Third", " Fourth", " Fifth", " Sixth" })); mList.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { close(); } }); open(); } public void initAnim() { // 采用了绝对布局,绝对布局是view的左上角从(0,0)开始 @SuppressWarnings("deprecation") final android.widget.AbsoluteLayout.LayoutParams lp = new android.widget.AbsoluteLayout.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, 0, 0); findViewById(R.id.slideout_placeholder).setLayoutParams(lp); // 屏幕的宽度 int displayWidth = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay().getWidth(); // 右边的位移量,60dp转换成px int sWidth = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 60, getResources() .getDisplayMetrics()); // 将快照向右移动的偏移量 final int shift = displayWidth - sWidth; // 向右移动的位移动画向右移动shift距离,y方向不变 mStartAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, shift, TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 0); // 回退时的位移动画 mStopAnimation = new TranslateAnimation(TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, -shift, TranslateAnimation.ABSOLUTE, 0, TranslateAnimation.ABSOLUTE, 0); // 持续时间 mStartAnimation.setDuration(DURATION_MS); // 动画完成时停留在结束位置 mStartAnimation.setFillAfter(true); mStartAnimation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { // 动画结束时回调 // 将imageview固定在位移后的位置 mCover.setAnimation(null); @SuppressWarnings("deprecation") final android.widget.AbsoluteLayout.LayoutParams lp = new android.widget.AbsoluteLayout.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT, shift, 0); mCover.setLayoutParams(lp); } }); mStopAnimation.setDuration(DURATION_MS); mStopAnimation.setFillAfter(true); mStopAnimation.setAnimationListener(new AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { finish(); overridePendingTransition(0, 0); } }); } public void open() { mCover.startAnimation(mStartAnimation); } public void close() { mCover.startAnimation(mStopAnimation); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // 摁返回键时也要触发动画 if (keyCode == KeyEvent.KEYCODE_BACK) { close(); return true; } return super.onKeyDown(keyCode, event); } }sample.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/inner_content" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@android:color/white" > <LinearLayout android:layout_width="fill_parent" android:layout_height="45dip" android:background="#bb000000" android:gravity="center_vertical" android:orientation="horizontal" > <Button android:id="@+id/sample_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="10dip" android:drawableTop="@drawable/menuicon" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="slide-out navigation" android:textColor="#ffffff" android:textSize="19sp" /> </LinearLayout> </RelativeLayout>main.xml
<?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/slideout_placeholder" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#777777" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:cacheColorHint="#00000000" /> </FrameLayout> <ImageView android:id="@+id/slidedout_cover" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="fitXY" /> </AbsoluteLayout>
最近一直在思考我的职业规划,我一直问自己真的喜欢做程序员吗???
毕业两年了,阴差阳错的走进了手机行业,第一年做在手机方案公司做展讯平台的MMI工程师,平时的主要工作就是改BUG, 包括各种死机,蓝屏的BUG,工作了一年,不想改BUG了,因为发现自己改了一年的BUG,写代码的能力依旧很差很差,然后辞职。目前外包到国内比较大的手机公司做驱动,当初是因为冲着这家公司的牌子,以及外包的工资还可以就去了,然后发现外包真的很苦逼,学到的东西有限不说,发现自己的工作还是在解各种乱七八糟的BUG。代码看的云里雾里,一直改着别人的BUG,总是缺少成就感。。。很迷茫!!
今天看到了老罗的一篇博客,题目是《创业降级论》http://www.douban.com/note/223883640/ 内容很苦逼,IT这个行业以前看似光鲜,其实没几个赚到钱的,整天坐在办公室里面加班,过劳死的很多。其实有的时候我看着满屏幕的代码,我都有砸电脑的冲动,我的青春难道就要献给这每天都解决不完的BUG。虽然我一直自称自己的IT届混的,其实问问自己,写过几行代码?做过几个应用,自己往往就答不上来......
我一直在反思,我为什么现在不快乐?虽然我一直很努力,拼命的学习,努力使得自己进步。最近,移动互联网炒得很火很火,我算是半个手机行业的人吧,但是和互联网基本不搭边。但是我觉得自己对这方面还是蛮感兴趣的,我在想我是不是要利用业余时间转行做应用?然后我开始打算学习IOS开发,目标是应用方面。。。我越来越发现自己的目标应该是通过做产品积累经验,然后转向市场运营方面的工作。但是前提是我有一定的技术功底。
所以我决定,我要努力转行做应用吧。虽然我知道做应用竞争很激烈,新技术更新很快,但是我觉得做出一款产品会让我自己有成就感,如果我能产品更加成功的推向市场,我会更加的有成就感。这应该就是我的目标吧。不知道我这个思想对不对?哪位大侠指出一下?
目前的打算是这两年,我要努力的技术,给自己充电,尽快的成长。
2楼karl1574天前 08:54我现在的公司也是手机业务这块的。加个好友认识下吧。我QQ:1576763631楼karl1574天前 08:52你好!目前我刚刚进入IT行业。公司业务基本上都是做软件和系统兼容测试。刚进来不知道,其实我也想做应用开发。但是没任何经验啊,现在只能先混个1年再说。确实找bug 修复bug对提高编程能力没多大提升,我感觉很迷茫。。。参考:http://www.cnblogs.com/highriver/archive/2011/12/18/2291965.html
通过对以上文章的拜读,我进一步加深了对线程同步锁的理解。
下面就根据自己的理解,进行的简单实例操作演示。
在看下面的代码前,强烈建议先拜读上面的文章。
源码下载:http://download.csdn.net/detail/yang_hui1986527/4423728
MainActivity.java
package com.snowdream.demo; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.View; import android.widget.TextView; public class MainActivity extends Activity { private static final int MSG_CLEAR = 0; private static final int MSG_UPDATE = 1; private final Object mObject = new Object(); private final String tag = "MainActivity"; ExecutorService pool = null; private static TextView mTextView = null; private static Handler mHandler = new Handler(){ public void handleMessage(Message msg){ switch (msg.what) { case MSG_CLEAR: mTextView.setText(""); break; case MSG_UPDATE: String str = (String)msg.obj; if (!TextUtils.isEmpty(str)) { mTextView.append(str); mTextView.append("\n"); } break; default: break; } }; }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); } private void initView() { mTextView = (TextView)findViewById(R.id.textView1); } private void initData() { pool = Executors.newFixedThreadPool(2); } @Override protected void onDestroy() { super.onDestroy(); pool.shutdown(); } public void OnButton1Click(View view) { int id = view.getId(); switch (id) { case R.id.button1: //synchronized(class) //synchronized(this) mHandler.sendMessage(mHandler.obtainMessage(MSG_CLEAR)); Sync1_Class sync1_Class = new Sync1_Class(); Sync1_Object sync1_Object = new Sync1_Object(); pool.execute(sync1_Class); pool.execute(sync1_Object); break; case R.id.button2: //synchronized(this) //synchronized(this) mHandler.sendMessage(mHandler.obtainMessage(MSG_CLEAR)); Sync2_Object_1 sync2_Object_1 = new Sync2_Object_1(); Sync2_Object_2 sync2_Object_2 = new Sync2_Object_2(); pool.execute(sync2_Object_1); pool.execute(sync2_Object_2); break; case R.id.button3: //synchronized(class) //synchronized(class) mHandler.sendMessage(mHandler.obtainMessage(MSG_CLEAR)); Sync3_Class_1 sync3_Class_1 = new Sync3_Class_1(); Sync3_Class_2 sync3_Class_2 = new Sync3_Class_2(); pool.execute(sync3_Class_1); pool.execute(sync3_Class_2); break; default: break; } } public class Sync1_Class implements Runnable { public void run() { synchronized(MainActivity.class){ for (int i = 0; i < 100; i++) { Log.i(tag, "Sync1_Class: "+ i); mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE, "Sync1_Class: "+ i)); } } } } public class Sync1_Object implements Runnable { public void run() { synchronized(mObject){ for (int i = 0; i < 100; i++) { Log.i(tag, "Sync1_Object: "+ i); mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE, "Sync1_Object: "+ i)); } } } } public class Sync2_Object_1 implements Runnable { public void run() { synchronized(mObject){ for (int i = 0; i < 100; i++) { Log.i(tag, "Sync2_Object_1: "+ i); mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE, "Sync2_Object_1: "+ i)); } } } } public class Sync2_Object_2 implements Runnable { public void run() { synchronized(mObject){ for (int i = 0; i < 100; i++) { Log.i(tag, "Sync2_Object_2: "+ i); mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE, "Sync2_Object_2: "+ i)); } } } } public class Sync3_Class_1 implements Runnable { public void run() { synchronized(MainActivity.class){ for (int i = 0; i < 100; i++) { Log.i(tag, "Sync3_Class_1: "+ i); mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE, "Sync3_Class_1: "+ i)); } } } } public class Sync3_Class_2 implements Runnable { public void run() { synchronized(MainActivity.class){ for (int i = 0; i < 100; i++) { Log.i(tag, "Sync3_Class_2: "+ i); mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE, "Sync3_Class_2: "+ i)); } } } } @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
activity_main.xml
<RelativeLayout 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" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" > <Button android:id="@+id/button1" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:onClick="OnButton1Click" android:text="Button1" /> <Button android:id="@+id/button2" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:onClick="OnButton1Click" android:text="Button2" /> <Button android:id="@+id/button3" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:gravity="center" android:onClick="OnButton1Click" android:text="Button3" /> </LinearLayout> <ScrollView android:id="@+id/scrollView1" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/linearLayout1" android:layout_toLeftOf="@+id/textView1" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="@dimen/padding_small" android:text="Loading..." tools:context=".MainActivity" /> </ScrollView> </RelativeLayout>
效果预览: