Android自定义控件:下拉菜单的实现与优化
source link: http://www.androidchina.net/3928.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
美团首页类似的下拉弹出菜单工程中经常遇到的控件,不同工程中菜单条目的类型与数量也不一样
所以需要根据实际需要填充不同内容。先写个demo,一倍不时之需吧。
既然每个项目用到的菜单样式不同,此时我们必须根据实际情况填充,这样就需要将容器和内容分开。
容器的画当然就使用popWindow了,我们需要在点击指定控件后弹出window,需要
1.指定当前window的位置及大小
2.指定window出方式
3.如果要求其他部分变暗,我们必须指定变暗部分的高度
内容需要被填充到容器中,根据不同的数据类型及需求,设置不同的页面填充。可以将其定义为**组合控件**或者一个**Holder**。
需要提供控件填充方法和数据刷新两个基本方法,同时还需要一个方法暴露一个View的引用,这样就可以将这个View填充到我们想添加的任何位置。
BaseHolder
/**
* Created by Administrator on 2015/10/30 0030.
*/
public
abstract
class
BaseHolder<T> {
private
View mView;
public
abstract
View initView();
public
abstract
void
refreshView(T info);
public
BaseHolder(){
mView = initView();
mView.setTag(
this
);
}
public
View getView(){
return
mView;
}
}
假定我们现在按下一个按键,然后弹出popwindow,此时我们需要继承一个Button,
复写Button的OnClick方法,从而实现点击按键在按键正下方弹出popwindow的效果。
public
class
PopMenuButton
extends
Button
implements
View.OnClickListener {
private
Context mCtx;
private
PopupWindow mPopupWindow;
private
LinearLayout mPopupWindowView;
//根布局设置为Button 弹出popwindow的位置可以以根布局为参照
private
View mRootView;
private
View mShodowView;
private
LinearLayout mContentView;
private
int
[] mLocation =
new
int
[
2
];
private
int
mStartY;
private
int
mScreenHeight;
public
PopMenuButton(Context context, AttributeSet attrs) {
super
(context, attrs);
mCtx = context;
mRootView =
this
;
}
public
PopMenuButton(Context context) {
super
(context);
mCtx = context;
mRootView =
this
;
}
@Override
protected
void
onFinishInflate() {
super
.onFinishInflate();
initPopWindow();
}
public
void
setContentView(View view){
LinearLayout.LayoutParams params =
new
LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
mContentView.addView(view, params);
}
private
void
initView(){
mPopupWindowView = (LinearLayout) View.inflate(mCtx, R.layout.popmenu_layout,
null
);
mContentView = (LinearLayout) mPopupWindowView.findViewById(R.id.rl_content);
mShodowView = mPopupWindowView.findViewById(R.id.rl_shodow);
mShodowView.setOnClickListener(
new
OnClickListener() {
@Override
public
void
onClick(View v) {
mPopupWindow.dismiss();
}
});
setOnClickListener(
this
);
}
private
void
initPopWindow(){
initView();
//获取按键的位置
mRootView.getLocationOnScreen(mLocation);
mStartY = mLocation[
1
] + mRootView.getHeight();
}
@Override
public
void
onClick(View v) {
if
(mPopupWindow ==
null
) {
//initPopWindow();
int
[] location =
new
int
[
2
];
this
.getLocationOnScreen(location);
//y轴起始位置
int
start = location[
1
] +
this
.getHeight() +
1
;
//测量屏幕的高度
int
screenHeight = ((Activity) mCtx).getWindowManager().getDefaultDisplay().getHeight();
//设置弹框的大小 弹框位置在按钮以下,占据所有屏幕
mPopupWindow =
new
PopupWindow(mPopupWindowView, ViewGroup.LayoutParams.MATCH_PARENT, screenHeight - start,
false
);
// mPopupWindow = new PopupWindow(mPopupWindowView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,false);
mPopupWindow.setBackgroundDrawable(
new
ColorDrawable(
0xb0000000
));
//mPopupWindow.setAnimationStyle(R.style.AnimationFade);
mPopupWindow.setAnimationStyle(R.style.popupAnimation);
mPopupWindow.setFocusable(
true
);
mPopupWindow.setOutsideTouchable(
true
);
}
if
(mPopupWindow.isShowing()) {
mPopupWindow.dismiss();
}
else
{
int
[] location1 =
new
int
[
2
];
this
.getLocationOnScreen(location1);
//设置弹框的位置
mPopupWindow.showAtLocation(mRootView, Gravity.NO_GRAVITY,
0
, location1[
1
]+
this
.getHeight()+
1
);
}
}
private
int
dip2px(Context context,
float
dpValue) {
final
float
scale = context.getResources().getDisplayMetrics().density;
return
(
int
) (dpValue * scale);
}
}
二级菜单Holder
假设我们当前要弹出一个二级菜单,我们可以将逻辑封装到一个Holder中,最终让holder为我们提供页面,直接将页面贴到容器中。
/**
* Created by vonchenchen on 2015/10/30 0030.
*/
public
class
DoubleListViewHolder
extends
BaseHolder<List<List<String>>> {
private
List<List<String>> mData;
private
ListView mLeftListView;
private
ListView mRightListView;
private
List<String> mLeftList;
private
List<String> mRightList;
private
TextListAdapter mLeftAdapter;
private
TextRightListAdapter mRightAdapter;
private
View mViewClickRecorder =
null
;
private
boolean
mFirstMesure =
true
;
@Override
public
View initView() {
View view = View.inflate(MyApplication.getContext(), R.layout.doublelistview_layout,
null
);
mLeftListView = (ListView) view.findViewById(R.id.ll_left);
mRightListView = (ListView) view.findViewById(R.id.ll_right);
mLeftListView.setOnItemClickListener(
new
AdapterView.OnItemClickListener() {
@Override
public
void
onItemClick(AdapterView<?> parent, View view,
int
position,
long
id) {
//如果点击条目,更换被点击条目的颜色
if
(mViewClickRecorder != view){
view.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_selected_color));
if
(mViewClickRecorder !=
null
) {
mViewClickRecorder.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_unselected_color));
}
mViewClickRecorder = view;
}
mRightList = mData.get(position+
1
);
mRightAdapter =
new
TextRightListAdapter(mRightList);
mRightListView.setAdapter(mRightAdapter);
}
});
return
view;
}
@Override
public
void
refreshView(List<List<String>> info) {
this
.mData = info;
mLeftList = info.get(
0
);
mLeftAdapter =
new
TextListAdapter(mLeftList);
mRightList = info.get(
1
);
mRightAdapter =
new
TextRightListAdapter(mRightList);
mLeftListView.setAdapter(mLeftAdapter);
mRightListView.setAdapter(mRightAdapter);
}
class
TextListAdapter
extends
MyAdapter{
public
TextListAdapter(List list) {
super
(list);
}
@Override
public
View getView(
final
int
position, View convertView, ViewGroup parent) {
TextViewHolder holder =
null
;
if
(convertView ==
null
){
holder =
new
TextViewHolder();
}
else
{
holder = (TextViewHolder) convertView.getTag();
}
convertView = holder.getView();
holder.refreshView((String) getItem(position));
//防止多次测量
if
(position ==
0
&& mFirstMesure){
mFirstMesure =
false
;
convertView.setBackgroundColor(MyApplication.getContext().getResources().getColor(R.color.normal_selected_color));
mViewClickRecorder = convertView;
}
return
convertView;
}
}
class
TextRightListAdapter
extends
MyAdapter{
public
TextRightListAdapter(List list) {
super
(list);
}
@Override
public
View getView(
final
int
position, View convertView, ViewGroup parent) {
TextViewHolder holder =
null
;
if
(convertView ==
null
){
holder =
new
TextViewHolder();
}
else
{
holder = (TextViewHolder) convertView.getTag();
}
convertView = holder.getView();
holder.refreshView((String) getItem(position));
return
convertView;
}
}
/**
* ListView 中的 Holder
*/
private
class
TextViewHolder
extends
BaseHolder<String>{
private
TextView mTextView;
@Override
public
View initView() {
View view = View.inflate(MyApplication.getContext(), R.layout.simpletext_item,
null
);
mTextView = (TextView) view.findViewById(R.id.tv_text);
return
view;
}
@Override
public
void
refreshView(String info) {
mTextView.setText(info);
}
}
}
将内容添加到容器中
调用的时候分为以下四步。这样,显示,逻辑和数据就自然分离开来了。
//创建容器
PopMenuButton mPopMenuButton = (PopMenuButton) findViewById(R.id.btn_pop);
//创建Holder,提供内容
DoubleListViewHolder holder =
new
DoubleListViewHolder();
//将 内容 贴到 容器 中
mPopMenuButton.setContentView(holder.getView());
//用数据刷新容器的显示内容
holder.refreshView(mLists);
git:https://git.oschina.net/vonchenchen/pulldownmenu.git
转载请注明:Android开发中文站 » Android自定义控件:下拉菜单的实现与优化
Recommend
-
46
JOJO是我看过脑洞最大的动漫(没有之一),每季必追 最近打算做简历,想自定义个能力分析图,首先就想到这里: 废话不多说,走起,噢啦,噢啦,噢啦,噢啦... 一、静态图的绘制 1.绘制外圈 为了减少变量值,让尺寸具有很好的联动性(等比扩缩),小黑条的长
-
40
零、前言 总算想到一个神级的自定义控件了 前方高能预警,萌新自带零食饮料 本文的前置知识你需简单了解:Android绘制函数图象及正弦函数的介绍 没错,今天玩自定义控件,和函数、录音有什么关系?用脚趾头稍微想一下就知道了... 废话不多说,看待仿效果:
-
9
在 React 里实现国旗下拉菜单漂洋过海来看你IT俱乐部-码出人生在 React 里实现国旗下拉菜单Dec 16, 2020re...
-
10
Android 自定义控件 优雅实现元素间的分割线 (支持3.0以下) 转...
-
9
Android 自定义控件 轻松实现360软件详情页_Hongyang-CSDN博客_android 自定义控件 转载请标明出处: http...
-
7
jQuery之使用slideToggle实现垂直下拉菜单 这篇文章发布于 2009年12月22日,星期二,03:30,归类于 jQuery相关。 阅读 78328 次,...
-
6
下拉菜单变了:Android 13版ColorOS系统截图曝光 2022-07-07 13:10 出处/作者:快科技 整合编辑:佚名 0
-
3
Android 心率动画自定义控件实现 2023年2月9日 | 最近更新于 下午2:36 Android心率曲线平移动画自定义控件实现详解,并附上GitHub完整实现仓库资源。 项目上需要实现一个心率曲线波动的自定...
-
3
QT实现可拖动自定义控件 使用QT实现自...
-
4
[MAUI程序设计] 用Handler实现自定义跨平台控件
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK