- 浏览: 433543 次
- 性别:
- 来自: 苏州
文章分类
最新评论
-
yehuiyan8002:
支持中文查询
快熟查找联系人 -
lehehe:
现成的接口,免费试用,http://www.haoservic ...
天气Widget -
D.Z:
android:focusable="false&q ...
CheckBox在ListView 而导致其OnItemClickListener不会被触发 -
freecode:
碰到该问题,CheckBox的android:focusabl ...
CheckBox在ListView 而导致其OnItemClickListener不会被触发 -
echohfut:
哥们,新博客是不是在墙外啊?不能访问。还有你怎么进行博客迁移的 ...
博客 迁移
大家对抽屉控件的第一反应就是系统提供的 如下:
其实 该控件的原理说白了 很简单 即:
* ViewGroup 如:LinearLayout 用于放置各种View
* Button 用于 展开/收起 ViewGroup
所以该控件的大致布局应如下:
<Panel> <Button /> <LinearLayout > <TextView /> <ImageView /> </LinearLayout> </Panel>
为了降低开发难度 我打算 定义 Panel extends LinearLayout
[代码 步骤]
1. 定义一些XML用到的属性
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Panel"> //动画演变时长 <attr name="animationDuration" format="integer" /> //摆放位置 只能取下面的4个值 <attr name="position"> <enum name="top" value="0" /> <enum name="bottom" value="1" /> <enum name="left" value="2" /> <enum name="right" value="3" /> </attr> //开合是否有动画效果 <attr name="animationEnable" format="boolean" /> </declare-styleable> </resources>
2. 一个标准的XML为:
<org.panel.Panel android:id="@+id/leftPanel" android:layout_width="wrap_content" android:layout_height="wrap_content" panel:position="left" panel:animationDuration="10" panel:animationEnable="true" android:layout_gravity="left" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" > <CheckBox android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Top Panel!" android:textSize="16dip" android:textColor="#eee" android:textStyle="bold" /> <EditText android:layout_width="200dip" android:layout_height="wrap_content" /> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:text="OK!" /> </LinearLayout> </org.panel.Panel>
3. 解析该XML 并设置之
public Panel(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel); mDuration = a.getInteger(R.styleable.Panel_animationDuration, 750); mPosition = a.getInteger(R.styleable.Panel_position, BOTTOM); isAnimation = a.getBoolean(R.styleable.Panel_animationEnable, true); a.recycle(); //根据mPosition 决定LinearLayout的android:orientation属性 mOrientation = (mPosition == TOP || mPosition == BOTTOM)? VERTICAL : HORIZONTAL; setOrientation(mOrientation); //初始化mHandle 背景图 initialHandlerBg(); }
4. 设定Button 背景图
//设置mHandle所用背景图 private void initialHandlerBg(){ if(mPosition == TOP){ mOpenedHandle = getResources().getDrawable(R.drawable.top_switcher_expanded_background); mClosedHandle = getResources().getDrawable(R.drawable.top_switcher_collapsed_background); } else if(mPosition == BOTTOM) { mOpenedHandle = getResources().getDrawable(R.drawable.bottom_switcher_expanded_background); mClosedHandle = getResources().getDrawable(R.drawable.bottom_switcher_collapsed_background); } else if(mPosition == LEFT) { mOpenedHandle = getResources().getDrawable(R.drawable.left_switcher_expanded_background); mClosedHandle = getResources().getDrawable(R.drawable.left_switcher_collapsed_background); } else if(mPosition == RIGHT) { mOpenedHandle = getResources().getDrawable(R.drawable.right_switcher_expanded_background); mClosedHandle = getResources().getDrawable(R.drawable.right_switcher_collapsed_background); } }
5. 取出其中的 ViewGroup & Button
//回调函数 界面初始化快结束时调用 用于得到 mHandle/mContent protected void onFinishInflate() { super.onFinishInflate(); //得到mHandle实例 mHandle = this.getChildAt(0); if (mHandle == null) { throw new RuntimeException("Your Panel must have a View - mHandle"); } mHandle.setOnClickListener(clickListener); //得到mContent实例 mContent = this.getChildAt(1); if (mContent == null) { throw new RuntimeException("Your Panel must have a View - mContent"); } //先移除mHandle/mContent 然后根据position决定二者的添加次序 removeView(mHandle); removeView(mContent); if (mPosition == TOP || mPosition == LEFT) { addView(mContent); addView(mHandle); } else { addView(mHandle); addView(mContent); } if (mClosedHandle != null) { mHandle.setBackgroundDrawable(mClosedHandle); } //隐藏 mContent mContent.setVisibility(GONE); }
6. 得到ViewGroup 宽度/高度 以决定动画演变范围
注意其位置 并非放在开始地方 因为那时候返回值都是0
@Override //回调函数 此时其内所有子View 宽度/高度 都已确定 protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mContentWidth = mContent.getWidth(); mContentHeight = mContent.getHeight(); paddingTop = this.getPaddingTop(); paddingLeft = this.getPaddingLeft(); }
7. 定义Button 响应事情 执行 开合ViewGroup
// 定义mHandle监听器 用于开合mContent OnClickListener clickListener = new OnClickListener(){ public void onClick(View v) { // TODO Auto-generated method stub if(!isContentExpand){ open(); } else { close(); } //置反 即:开-合-开-合-开-... isContentExpand = !isContentExpand; } };
8. 定义开合的回调函数 具体效果 见:setOnClickListener(OnClickListener listener)
//回调函数 用于监听 Panel 的开合 效果见:setOnClickLstener(OnClickListener listener) public static interface OnPanelListener { //- open public void onPanelOpened(Panel panel); //- close public void onPanelClosed(Panel panel); }
10. 开 即: 打开ViewGroup
public void open(){ if(isAnimation){ doAnimationOpen(); } else { doOpen(); } } public void doOpen(){ mContent.setVisibility(VISIBLE); } public void doAnimationOpen(){ mContent.setVisibility(VISIBLE); post(aOpen); }
11. 定义开的Animation
//- open Runnable aOpen = new Runnable() { public void run() { TranslateAnimation animation; int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0; int calculatedDuration = 0; if(mPosition == TOP){ fromYDelta = -1 * mContentHeight; toXDelta = 0; calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; } else if(mPosition == BOTTOM){ fromYDelta = paddingTop; toYDelta = fromYDelta + 1 * mContentHeight; calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; } else if(mPosition == LEFT){ fromXDelta = -1 * mContentWidth; toXDelta = 0; calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth; } else if(mPosition == RIGHT){ fromXDelta = paddingLeft; toXDelta = fromYDelta + 1 * mContentHeight; calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; } animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta); animation.setDuration(calculatedDuration); animation.setAnimationListener(aOListener); startAnimation(animation); } };
12. 合 即:关闭ViewGroup
public void close(){ if(isAnimation){ doAnimationClose(); } else { doClose(); } } public void doClose(){ mContent.setVisibility(GONE); } public void doAnimationClose(){ post(aClose); }
13. 定义合的Animation
//- close Runnable aClose = new Runnable() { public void run() { TranslateAnimation animation; int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0; int calculatedDuration = 0; if(mPosition == TOP){ toYDelta = -1 * mContentHeight; calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; } else if(mPosition == BOTTOM){ fromYDelta = 1 * mContentHeight; toYDelta = paddingTop; calculatedDuration = mDuration * Math.abs(toYDelta - fromYDelta) / mContentHeight; } else if(mPosition == LEFT){ toXDelta = -1 * mContentWidth; calculatedDuration = mDuration * Math.abs(toXDelta - fromXDelta) / mContentWidth; } else if(mPosition == RIGHT){ } animation = new TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta); animation.setDuration(calculatedDuration); animation.setAnimationListener(aCListener); startAnimation(animation); } };
14. 定义二者Animation 的回调函数 即:结束后 更改Button背景图 通知OnPanelListener
//善后工作 比如:改变mHandle背景图 通知开合监听器 private void postProcess() { // to update mHandle 's background if (!isContentExpand ) { mHandle.setBackgroundDrawable(mClosedHandle); } else { mHandle.setBackgroundDrawable(mOpenedHandle); } // invoke listener if any if (panelListener != null) { if (isContentExpand) { panelListener.onPanelOpened(Panel.this); } else { panelListener.onPanelClosed(Panel.this); } } }
15. emulator 运行截图:
* 先贴其布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:panel="http://schemas.android.com/apk/res/org.panel" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <org.panel.Panel android:id="@+id/leftPanel" android:layout_width="wrap_content" android:layout_height="wrap_content" panel:position="left" panel:animationDuration="10" panel:animationEnable="true" android:layout_gravity="left" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" > <CheckBox android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="Top Panel!" android:textSize="16dip" android:textColor="#eee" android:textStyle="bold" /> <EditText android:layout_width="200dip" android:layout_height="wrap_content" /> <Button android:layout_width="100dp" android:layout_height="wrap_content" android:text="OK!" /> </LinearLayout> </org.panel.Panel> <org.panel.Panel android:id="@+id/rightPanel" android:layout_width="wrap_content" android:layout_height="wrap_content" panel:position="right" panel:animationDuration="10" panel:animationEnable="true" android:layout_gravity="right" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" /> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/beijing4_b" /> </LinearLayout> </org.panel.Panel> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="16dip" android:textColor="#ddd" android:text="other area!!!!!!!!" /> <Button android:id="@+id/button" android:layout_width="100dp" android:layout_height="wrap_content" android:text="Yes!" /> </LinearLayout> </LinearLayout>
* 运行截图:
- 开
- 合
完工!
发表评论
-
滑动抽屉 另一种解决办法
2010-07-09 17:43 0滑动抽屉 -
Spinner 定制化 增强版
2010-07-09 14:34 2609Spinner 作为下拉选 ... -
ListView 内容之分批显示
2010-06-25 20:38 5923ListView 内容循环显示 大家试想 假如 ... -
MediaScanner 研究
2010-06-23 15:21 3169MediaScanner 之所以拿MediaSc ... -
CheckBox在ListView 而导致其OnItemClickListener不会被触发
2010-06-22 20:55 19013CheckBox在ListView 而导致其OnItemCli ... -
获取Launcher 启动列表
2010-06-22 10:09 3138获取Launcher 启动列表 即 列出所有Launc ... -
PreferenceActivity 全接触
2010-06-19 12:53 9439PreferenceActivity 为了引入 ... -
android src 下载 编译 安装 全接触
2010-06-12 14:44 0android src - download install ... -
Intent.createChooser() 妙用
2010-06-12 11:14 5955Intent.createChooser(ntent targ ... -
SMS管理:收信箱 发信息 编写新信息
2010-06-07 08:14 14445SMS管理 [功能] 1. 收信箱:显示 ... -
求 android 手机 帮忙测试sms服务系统 谢谢
2010-06-05 08:25 1451Hi guys, 最近一段时间没有更新blog 因为一 ... -
流媒体 播放 理论篇
2010-05-28 14:42 2222流媒体播放 之所以为理论篇 因为该篇仅实现了播放功能 ... -
NDK 搭建与HelloWorld
2010-05-19 09:48 3225NDK [前提] 1. Cygwin 用于安装 ... -
自定义字体
2010-05-15 10:49 1221自定义字体: []代码 步骤] 1 ... -
模糊查找 再深入
2010-05-15 09:41 3158模糊查找 再深入 应某位大哥要求 再次对 SQLite ... -
快捷方式Bar + ViewGroup - 自定义
2010-05-09 09:20 2470TabActivity - 自定义 其实 这篇感觉极鸡 ... -
View 拖动&插入 研究
2010-05-09 07:14 3984View 拖动&插入 即: ... -
带图标 快捷键 Menu - 终极版
2010-05-04 20:23 1837Menu 改头换面 扩展如下: 1. 图标化文字 2 ... -
*.gif 解码 - 实践
2010-05-02 18:58 1734*.gif decode 前面已经说过 今天不打算再说了 ... -
*.gif 解码 - 理论
2010-05-01 21:11 1522我们知道Android 默认是不支持*.gif 的 但是 ...
相关推荐
在Android应用开发中,滑动抽屉Panel是一种常见的设计模式,它允许用户通过从屏幕边缘向内滑动来显示或隐藏附加内容。本资源“自定义Android滑动抽屉Panel.zip”提供了一个自定义实现这一功能的示例,包含源码和相关...
在C#中,我们可以利用控件(如Panel或Form)的移动和大小调整功能来实现抽屉效果。以下是一些关键步骤: 1. 创建主窗体:首先,创建一个主窗体作为QQ界面的基础,设置其大小和布局。你可以使用Visual Studio的窗体...
在Android应用开发中,抽屉组件(Drawer Layout)是一种常见的...ExPanel(1)作为一个示例,为我们提供了一种可能的实现方式,通过研究其源码,我们可以学习到更多的技巧和最佳实践,进一步提升我们的Android开发能力。
例如,`Switcher.class`可能表示一个自定义的切换视图类,`Panel.class`可能是实现抽屉效果的类,而`TestInterpolators$2.class`可能是一个测试不同动画插值器效果的辅助类。 综上所述,这个压缩包是一个全面的...
"core-drawer-panel"是基于Polymer 0.5框架的一个...对于想要学习或重温这个组件的开发者,可以从名为"core-drawer-panel-master"的压缩包文件中获取源代码,研究其工作原理,但应意识到这只是一个历史性的参考资料。
在这里,开发者可能定义了一个隐藏的Panel或者UserControl作为菜单容器,然后在用户触发特定事件(如点击按钮)时,通过调整其位置和宽度来模拟抽屉滑出的效果。这通常涉及到对控件的Size、Location属性的动态修改,...
例如,一个常见的自定义Panel是底部导航抽屉,用户可以从中选择不同的功能模块。 2. 空键(Empty View): 空键是当数据为空时展示的一种特殊视图,它向用户传达了当前无数据可用的信息。在设计用户界面时,为了...
项目中可能包含的Widgets有:滑动面板(SlidingPanel)、折叠面板(CollapsiblePanel)、抽屉面板(DrawerPanel)等。这些Widgets通常具有自定义布局、动画效果和触摸交互特性,使得开发者可以轻松地定制符合应用...
侧窗是jQuery Mobile中的一种布局元素,常用于实现类似抽屉的效果,可以隐藏或显示附加信息。创建侧窗需要通过HTML5的`<div>`标签,并设置相应的类名,如`<div data-role="panel" id="myPanel">`。通过JavaScript...
在Qt5框架中,`QSidePanel`是一个自定义控件,它被设计用来作为界面中的侧边栏或抽屉式面板。这个组件通常用于显示附加信息、菜单选项或者工具栏,可以方便地进行展开和收起,为用户提供更加灵活的交互体验。`...
3. **侧滑面板(Swipeable Panel)**:侧滑面板通常用于实现类似抽屉式的效果,比如谷歌地图中的侧滑导航栏。可以使用CoordinatorLayout结合Behavior来实现,也可以使用DrawerLayout。主要关注滑动手势的识别和面板...
1. **Android Sliding Up Panel**:这是一个可滑动的顶部和底部面板库,可以用于创建类似Google Play音乐应用的侧滑效果。 2. **Android DrawerLayout**:这是Android SDK中内置的一个组件,用于创建抽屉式导航菜单...
这个项目主要是为 iOS 应用程序提供一种灵活的、可自定义的面板(Panel)展示方式。在 iOS 开发中,面板通常用于创建滑出式菜单、模态视图或者浮动操作按钮等交互元素,为用户界面增加丰富的动态效果。 【描述】...
向右滑动,则会隐藏,通常用于实现类似抽屉式的导航菜单。 要实现部分可见和淡入淡出效果,开发者需要对SlidingPaneLayout的一些关键属性进行调整。例如,可以设置`overhangSize`属性,使得滑动视图在完全滑出前...
这部分内容讨论了不同的导航模式,如抽屉式导航栏、底部导航栏等,并给出了具体的实现建议。 #### 二十、ActionBar - 动作栏 动作栏是Android应用中非常重要的组成部分。这部分内容介绍了如何设计和实现动作栏,使...