模仿QQ侧滑样式,借鉴了张鸿洋的最简单侧滑

来源:互联网 发布:java编译代码 编辑:程序博客网 时间:2024/06/05 21:11

看到QQ的侧滑效果,感觉太帅气了,总感觉要何等大神才能写的出来呢,开始还觉得很难,可是发现一个项目需要这种效果,没办法,谁较我们是程序猿呢,网上去找呗,第一眼就看到了张鸿洋的最简单侧滑,感觉特霸气,赶紧进去膜拜一下,然后下载下来分析,发现确实是最简单的了,在理解到原理过后,就发现一个小bug,因为ScrollView的滑动问题,如果已经滑动到最后一项了,但是如果再滑动一下,界面也是可以滑动的,虽然无伤大雅,但是总感觉不如qq的舒服,因为qq的就只能把菜单划出来过后就不能再向右划了,诸如此类,我也想解决,奈何技术不到家,解决不了,然后就看到一个继承FrameLayout的侧滑效果,看到的是那种直接划过来划过去,没有界面大小变化的,我就想能不能把这个和张鸿洋的结合起来,实现QQ的样式,然后就付诸实际行动了,

先来说一下思路吧:既然继承了FrameLayout,肯定就要了解他,FrameLayout的子控件全是叠加的,这样一想,就可以把qq的那种效果分为两个界面,菜单界面和内容界面,加载的时候让内容界面覆盖菜单界面,在滑动的时候吧内容界面移开,显示菜单界面,嗯,就是这么简单,不过我技术不到家,代码有点乱,这直接贴代码,第一次写帖子,大家多多包涵

package com.mypublicclass.view;import com.example.mypublicclass.R;import com.nineoldandroids.view.ViewHelper;import android.R.integer;import android.content.Context;import android.drm.DrmStore.Action;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.ViewTreeObserver.OnTouchModeChangeListener;import android.view.WindowManager;import android.view.animation.Animation;import android.view.animation.AnimationSet;import android.view.animation.AnimationUtils;import android.view.animation.TranslateAnimation;import android.widget.FrameLayout;import android.widget.LinearLayout;/** * @author yhl * @date 创建时间:2015年6月19日 上午9:20:47 * @version 1.0 * @updatetime * @modifier * @Deprecated 侧滑1 */public class SlidingFView extends FrameLayout {/** 屏幕的宽度 */private int screenWidth;/** 菜单的宽度 */private int menuWidth;/** 菜单宽度的的1/3,用来比较手势的位置,好来是左划还是右划 ,只是名字取的差了 点 */private int menuHintWidth;/** 菜单距离右边的距离,单位不知道 */private int menuPaddintRight = 70;/** 菜单打开的状态 */private boolean isOpen;/** 这个不晓得干嘛的,反正一起弄来了 */private boolean once;/** 菜单栏 */private ViewGroup mMenu;/** 内容栏 */private ViewGroup mContext;/** 按下的X */private float startX;/** 当前x的位置 */private int x = 0;/** 是否禁止启用侧滑,因为好些应用都是同一个界面,改了布局就不让划了,false就是不禁止 */private boolean ban = false;private Context context;public SlidingFView(Context context) {super(context, null, 0);initView(context);// TODO Auto-generated constructor stub}public SlidingFView(Context context, AttributeSet attrs) {super(context, attrs, 0);initView(context);// TODO Auto-generated constructor stub}public SlidingFView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);initView(context);// TODO Auto-generated constructor stub}private void initView(Context context) {screenWidth = getScreenWidth(context);menuWidth = screenWidth - menuPaddintRight;menuHintWidth = menuWidth * 1 / 3;isOpen = false;this.context = context;}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {// TODO Auto-generated method stubsuper.onLayout(changed, left, top, right, bottom);if (changed) {once = true;}}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);if (!once) {mMenu = (ViewGroup) getChildAt(0);// 得到布局里面的第一个子布局mContext = (ViewGroup) getChildAt(1);// 得到第二个子布局mMenu.getLayoutParams().width = menuWidth;mContext.getLayoutParams().width = screenWidth;}}@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {// TODO Auto-generated method stubswitch (ev.getAction()) {case MotionEvent.ACTION_DOWN:startX = ev.getX();break;case MotionEvent.ACTION_MOVE:if (!ban) {float scrollx = startX - ev.getX();if (scrollx < 0) {// 如果是右划if (!isOpen) {if (ev.getX() <= menuWidth) {x = (int) -scrollx;Message msg = new Message();msg.what = 1;msg.arg1 = x;handler.sendMessage(msg);}}} else if (scrollx > 0) {// 如果是左划if (isOpen) {x = (int) Math.abs(((int) menuWidth - Math.abs(scrollx)));if (menuWidth - Math.abs(scrollx) >= 0) {Message msg = new Message();msg.what = 1;msg.arg1 = x;handler.sendMessage(msg);}}}}break;case MotionEvent.ACTION_UP:float scrollX = startX - ev.getX();if (!ban) {if (scrollX < 0) {// 向右划动x = (int) Math.abs(scrollX) > menuWidth ? menuWidth: (int) Math.abs(scrollX);if (x >= menuHintWidth) {if (!isOpen) {openMenu();}} else {if (!isOpen) {// 这里说如果没有打开,就关闭菜单,理解起来可能有点矛盾,解释一下,这里执行,如果没有划到一半,就返回刚才的状态,所以才有了一个这个closeMenu();}}} else if (scrollX > 0) {// 向左滑动x = (int) Math.abs(((int) menuWidth - Math.abs(scrollX)));if (Math.abs(scrollX) >= menuHintWidth) {if (isOpen) {// 为啥我要在这里认证是否打开菜单,而不去方法里面去认证,因为上面那个说明了的,没办法closeMenu();}} else {if (isOpen) {openMenu();}}}}break;default:break;}return super.dispatchTouchEvent(ev);}/** * 禁止侧滑 */public void setBan() {this.ban = true;}/** * 启用侧滑 */public void setEnable() {this.ban = false;}public boolean getBan() {return ban;}public void setBan(boolean ban) {this.ban = ban;}/** * 操作菜单栏 */public void operation() {if (!ban) {if (isOpen) {// 关闭菜单closeMenu();} else {openMenu();}}}/** * 关闭菜单 */private void closeMenu() {// 关闭菜单isOpen = false;i = x;new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubtry {for (; i >= 0; i--) {Thread.sleep(1);Message msg = new Message();msg.what = 1;msg.arg1 = i;handler.sendMessage(msg);}Message msg = new Message();msg.what = 2;handler.sendMessage(msg);} catch (Exception e) {// TODO: handle exception}}}).start();}/** * 开启菜单 */private void openMenu() {isOpen = true;i = x;// 开启菜单,说白了,这里打开菜单就是把主界面向右移动,菜单界面由无到有显示new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubtry {for (; i < menuWidth; i++) {Thread.sleep(1);Message msg = new Message();msg.what = 1;msg.arg1 = i;handler.sendMessage(msg);}Message msg = new Message();msg.what = 2;handler.sendMessage(msg);} catch (Exception e) {// TODO: handle exception}}}).start();}int i = 0, j;private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {if (msg.what == 1) {if (!ban) {int x1 = msg.arg1;ViewHelper.setTranslationX(mContext, x1);// 移动float scale = x1 * 1.0f / menuWidth;// 滑动的距离占菜单的百分比float leftScale = 1 - 0.3f * (1 - scale);// 左边菜单的变化样式float rightScale = 0.8f + (1 - scale) * 0.2f;// 右边内容的变化样式// 放大和缩小ViewHelper.setScaleX(mMenu, leftScale);// 规模ViewHelper.setScaleY(mMenu, leftScale);ViewHelper.setPivotX(mMenu, 0.5f);// 转轴ViewHelper.setPivotY(mContext, menuWidth);// 设置透明度ViewHelper.setAlpha(mMenu, 0.4f + 0.6f * (scale + 0.01f));//计算过,scale最大的时候也没到1.0,所以我加了0.01fViewHelper.setPivotX(mContext, 0);// 转轴ViewHelper.setPivotY(mContext, mContext.getHeight() / 2);ViewHelper.setScaleX(mContext, rightScale);ViewHelper.setScaleY(mContext, rightScale);}} else if (msg.what == 2) {if (isOpen) {i = x = menuWidth;} else {i = x = 0;}}}};/** * 得到屏幕的宽度 *  * @param context * @return */public static int getScreenWidth(Context context) {WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);int width = wm.getDefaultDisplay().getWidth();int height = wm.getDefaultDisplay().getHeight();return width;}private void L(String string) {Log.e("打印数据", string);}}

代码有点乱,滑动的方式我用的很笨的线程来滑动,感觉应该会有点问题,希望大家多多指教,里面用到了一个包,从张鸿洋的侧滑里找到的

然后我们看看activity,

package com.example.mypublicclass;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;import android.widget.Toast;import com.mypublicclass.view.SlidingFView;/** * @author yhl * @date 创建时间:2015年6月19日 下午1:36:15 * @version 1.0 * @updatetime * @modifier * @Deprecated 侧滑1,重写FrameLayout */public class SlidingFActivity extends Activity implements OnClickListener {private SlidingFView fView;private ListView listView;private List<String> list = new ArrayList<String>();private adapter ad;private TextView txt_1, txt_2, txt_3, txt_4, txt_5, txt_6;@Overrideprotected void onCreate(Bundle savedInstanceState) {// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_slidingf);fView = (SlidingFView) findViewById(R.id.fView);findViewById(R.id.btn_open).setOnClickListener(this);// listView = (ListView) findViewById(R.id.lst);// listView.setOnItemClickListener(new OnItemClickListener() {//// @Override// public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,// long arg3) {// // TODO Auto-generated method stub// makeToast("测试" + (arg2 + 1) + "条");// }// });// ad = new adapter();// listView.setAdapter(ad);getData();initView();}private void initView() {// TODO Auto-generated method stubtxt_1 = (TextView) findViewById(R.id.txt_1);txt_2 = (TextView) findViewById(R.id.txt_2);txt_3 = (TextView) findViewById(R.id.txt_3);txt_4 = (TextView) findViewById(R.id.txt_4);txt_5 = (TextView) findViewById(R.id.txt_5);txt_6 = (TextView) findViewById(R.id.txt_6);txt_1.setOnClickListener(this);txt_2.setOnClickListener(this);txt_3.setOnClickListener(this);txt_4.setOnClickListener(this);txt_5.setOnClickListener(this);txt_6.setOnClickListener(this);}private void makeToast(String string) {Toast.makeText(this, string, 3).show();}/** * 添加数据 */private void getData() {for (int i = 0; i < 15; i++) {list.add("测试" + (i + 1) + "条");}// ad.notifyDataSetChanged();}@Overridepublic void onClick(View arg0) {switch (arg0.getId()) {case R.id.btn_open:fView.operation();break;case R.id.txt_1:makeToast("测试1");break;case R.id.txt_2:makeToast("测试2");break;case R.id.txt_3:makeToast("测试3");break;case R.id.txt_4:makeToast("测试4");break;case R.id.txt_5:makeToast("测试5");break;case R.id.txt_6:if (fView.getBan()) {fView.setEnable();txt_6.setText("已开启");} else {fView.setBan();txt_6.setText("已关闭");}break;default:break;}}private class adapter extends BaseAdapter {@Overridepublic int getCount() {// TODO Auto-generated method stubreturn list.size();}@Overridepublic Object getItem(int arg0) {// TODO Auto-generated method stubreturn list.get(arg0);}@Overridepublic long getItemId(int arg0) {// TODO Auto-generated method stubreturn arg0;}Holder hd = null;@Overridepublic View getView(int id, View cv, ViewGroup arg2) {// TODO Auto-generated method stubif (cv == null) {hd = new Holder();cv = LayoutInflater.from(SlidingFActivity.this).inflate(R.layout.cehua_item, null);hd.textView = (TextView) cv.findViewById(R.id.txt);cv.setTag(hd);} else {hd = (Holder) cv.getTag();}hd.textView.setText(list.get(id));return cv;}private class Holder {TextView textView;}}}
这里测试了一下ListView在里面会不会冲突,这里是不会冲突的,测试过,因为不会弄动态图,这里就不贴图了,

布局文件就不贴了,就是这个自定义控件包含了两个布局,一个菜单的布局,一个内容的布局

至于那个包,额,我还不晓得咋个发布文件到这上面委屈,自己要的话,就去下载张鸿洋源码下载,借鉴他的就很容易看懂我的,张兄,这先谢过了

0 0
原创粉丝点击