安卓无线点餐系统客户端——自定义之ScrollView餐桌

本文介绍如何通过自定义ScrollLayout实现界面间的滑动切换效果。文章详细讲解了自定义ViewGroup的过程,包括重写onLayout和onMeasure方法,并提供了一种使用自定义GridView的实现方案。

参考的一篇文章  :http://my.oschina.net/sfshine/blog/151673

先看一下做出来的效果图

可以滑动切换界面 ,这就要用到了自定义的ScrollLayout了,听说每个安卓程序员都要学会自定义ScrollView,好吧,今天我就边学边用。

可以这样理解,要做出滑动的效果,必须定义一个大于屏幕宽度的Layout,然后通过划动,在屏幕显示形成切换效果。


 之前也有用过ViewPage+Fragment也可以达成这样的效果,不过两者区别较大。

自定义ScrollLayout,继承ViewGroup,主要是重写onLayout() 和 onMeasure()方法。

package com.lin.helper;



import android.R.integer;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;

import android.view.ViewGroup;
import android.widget.Scroller;

public class MyScrollLayout extends ViewGroup {

	private VelocityTracker mVelocityTracker;//判断甩手姿势
	private static final int SNAP_VELOCITY = 600; //定义翻页的速度
	private Scroller mScroller;//
	private int mCurScreen;
	private int mDefaultScreen;
	private float mLastMotionX;
	
	private OnViewChangeListener mOnViewChangeListener; //自定义的接口类

	public MyScrollLayout(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		init(context);
	}
	public MyScrollLayout(Context context,AttributeSet attrs){
		super(context, attrs);
		init(context);
	}
	public MyScrollLayout(Context context, AttributeSet attrs, int defStyle)
	{
		super(context, attrs, defStyle);
		init(context);
	}
	
	private void init(Context context)
	{
		//初始化数据
		mCurScreen = mDefaultScreen;
		mScroller = new Scroller(context);//自定义Scoller,当滑动时View不会滚动
	}
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		// TODO Auto-generated method stub
		if (changed) {
			//view有新的尺寸或位置
			int childLeft = 0 ;
			final int childCount = getChildCount();
			for(int i =0;i<childCount;i++)
			{
				//生成View(滑动的页面)
				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) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		final int Width = MeasureSpec.getSize(widthMeasureSpec);
		final int WidthMode = MeasureSpec.getMode(widthMeasureSpec);
		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 detla = whichScreen * getWidth() - getScrollX();
			mScroller.startScroll(getScrollX(), 0, detla, 0, Math.abs(detla)*2);//设置切换的效果
			mCurScreen = whichScreen;
			invalidate();//重画Layout
			if (mOnViewChangeListener!=null) {
				mOnViewChangeListener.OnViewChange(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
		final int action = event.getAction();
		final float x = event.getX();
		final float y = event.getY();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			//Log.i("", "actiondown");
			if (mVelocityTracker==null) {
				mVelocityTracker = VelocityTracker.obtain();
				mVelocityTracker.addMovement(event);
			}
			if (!mScroller.isFinished()) {
				mScroller.abortAnimation();
			}
			mLastMotionX = x;
			break;
		case MotionEvent.ACTION_MOVE:
			int deltaX =(int)( mLastMotionX - x);
			if (IsCanMove(deltaX)) {
				if (mVelocityTracker!=null) {
					mVelocityTracker.addMovement(event);
				}
				mLastMotionX = x;
				scrollBy(deltaX, 0);
			}
			break;
		case MotionEvent.ACTION_UP:
			int VelocityX = 0;
			if (mVelocityTracker!=null) {
				mVelocityTracker.addMovement(event);
				mVelocityTracker.computeCurrentVelocity(1000);
				VelocityX = (int)mVelocityTracker.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;
			}
			break;
		}
		return true;
	}
	
	public boolean IsCanMove(int deltaX)
	{
		if(getScrollX()<=0 && deltaX<0){
			return false;
		}
		if (getScrollX()>= (getChildCount()-1)*getWidth() && deltaX > 0  ) {
			return false;
		}
		return true;
	}
	public void SetOnViewChangeListenner(OnViewChangeListener listener)
	{
		mOnViewChangeListener = listener;
	}
	
}

一个空白的自定义ScrollLayout就出来了。然后是可以在里面放Gridview,也就是子View,需要多少个页面就可以在xml布局里放多少个Gridview

这里还是用到了自定义的GridView,更美观一些。

package com.lin.helper;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.GridView;

public class MyGridView extends GridView{
	public MyGridView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	//自定义GridView 因为ScrollLayout与GridView都有滚动条,当他们嵌套在一起就会出现问题,所以自定义了一个GridView
	//重写了onMeasure()方法使其不出现滚动条
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2, MeasureSpec.AT_MOST);
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
}
之后就是在布局里应用这两个自定义的组件,跟平常一样


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    android:background="@drawable/choose_default">
    
    <LinearLayout
        android:id="@+id/c_taglayout"
	    android:layout_width="fill_parent"
	    android:layout_height="wrap_content"
	    android:background="@android:color/background_light"
	    android:orientation="horizontal">
	    
	    <TextView
	        android:id="@+id/choose_back" 
	        android:layout_width="wrap_content"
	        android:layout_height="32dp"
	        android:gravity="left"
	        android:background="@drawable/back"
	        android:textColor="#EC6806"
	        android:layout_marginLeft="10dp"
	        />

	    <TextView
	        android:id="@+id/choose_tag"
	        android:layout_width="fill_parent"
	        android:layout_height="32dp"
	        android:layout_marginTop="10dp"
	        android:layout_marginLeft="-50dp"
	        android:gravity="center_horizontal"
	        android:text="@string/choose_tag"
	        android:textColor="@android:color/black"
	        android:textSize="18sp" />
	   
	</LinearLayout>
    
    <com.lin.helper.MyScrollLayout 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/ScrollLayout"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/c_taglayout"
        >
       
      
        <com.lin.helper.MyGridView 
            android:id="@+id/gridview_01"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:columnWidth="90dp"
            android:horizontalSpacing="10dp"
            android:numColumns="auto_fit"
            android:stretchMode="columnWidth"
            android:verticalSpacing="10dp"
            >
            
            
        </com.lin.helper.MyGridView>
     
       <com.lin.helper.MyGridView 
            android:id="@+id/gridview_02"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:columnWidth="90dp"
            android:horizontalSpacing="10dp"
            android:numColumns="auto_fit"
            android:stretchMode="columnWidth"
            android:verticalSpacing="10dp"
           ></com.lin.helper.MyGridView>
        
       <com.lin.helper.MyGridView 
            android:id="@+id/gridview_03"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:columnWidth="90dp"
            android:horizontalSpacing="10dp"
            android:numColumns="auto_fit"
            android:stretchMode="columnWidth"
            android:verticalSpacing="10dp"
           ></com.lin.helper.MyGridView>
       
    </com.lin.helper.MyScrollLayout>
    
    <!-- 底部小圆点 -->
    <LinearLayout 
        
        android:id="@+id/llayout"
        android:orientation="horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="24dp"
        >
        <ImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:padding="15dp"
            android:clickable="true"
            android:src="@drawable/notcurrent"
            android:contentDescription="@null"
            />
        <ImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:padding="15dp"
            android:clickable="true"
            android:src="@drawable/notcurrent"
            android:contentDescription="@null"
            />
        <ImageView 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:padding="15dp"
            android:clickable="true"
            android:src="@drawable/notcurrent"
            android:contentDescription="@null"
            />
        
    </LinearLayout>
    
    

</RelativeLayout>
剩下的都比较简单啦。看看代码就好。

这是主Activity

package com.lin.view;

import java.util.ArrayList;
import java.util.HashMap;

import com.example.order_client.R;
import com.lin.helper.MyGridView;
import com.lin.helper.MyScrollLayout;
import com.lin.helper.OnViewChangeListener;

import android.R.integer;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class ChooseTableActivity extends Activity implements OnViewChangeListener ,OnClickListener,OnItemClickListener{
 
	private MyScrollLayout scrollLayout;
	private MyGridView myGridView_01;
	private MyGridView myGridView_02;
	private MyGridView myGridView_03;
	private ImageView[] imageViews;
	private int mViewCount;
	private int mCurSel;
	private  TextView c_tagView;
	private  TextView c_backView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_choosetable);
		scrollLayout = (MyScrollLayout)findViewById(R.id.ScrollLayout);
		myGridView_01 = (MyGridView)findViewById(R.id.gridview_01);
		myGridView_02 = (MyGridView)findViewById(R.id.gridview_02);
		myGridView_03 = (MyGridView)findViewById(R.id.gridview_03);
		c_tagView = (TextView)findViewById(R.id.choose_tag);
		c_backView = (TextView)findViewById(R.id.choose_back);
		c_backView.setOnClickListener(this);
		LinearLayout layout = (LinearLayout)findViewById(R.id.llayout);
		myGridView_01.setAdapter(getMeunAdapter());
		myGridView_02.setAdapter(getMeunAdapter());
		myGridView_03.setAdapter(getMeunAdapter());
		myGridView_01.setOnItemClickListener(this);
		myGridView_02.setOnItemClickListener(this);
		myGridView_03.setOnItemClickListener(this);
		mViewCount = scrollLayout.getChildCount();
		imageViews = new ImageView[mViewCount];
		for (int i = 0; i < mViewCount; i++) {
			//
			imageViews[i]=(ImageView)layout.getChildAt(i);
			imageViews[i].setEnabled(true);
			imageViews[i].setOnClickListener(this);
			imageViews[i].setTag(i);
		}
		mCurSel = 0;
		imageViews[mCurSel].setEnabled(false);
		imageViews[mCurSel].setImageDrawable(getResources().getDrawable(R.drawable.current));
		scrollLayout.SetOnViewChangeListenner(this);
		
	}

	private void setCurPoint(int index)
	{
		//底部小圆点
		if (index<0 ||index == mCurSel || index > mViewCount-1) {
			return;
		}
		imageViews[mCurSel].setEnabled(true);
		imageViews[index].setEnabled(false);
		imageViews[mCurSel].setImageDrawable(getResources().getDrawable(R.drawable.notcurrent));
		imageViews[index].setImageDrawable(getResources().getDrawable(R.drawable.current));
		mCurSel = index ;
		c_tagView.setText(index+1+"楼");
		
	}
	
	
	
	@Override
	public void OnViewChange(int view) {
		// TODO Auto-generated method stub
		setCurPoint(view);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		if(v.getClass()==ImageView.class)
		{
			//点击小圆点
			int pos =(Integer) v.getTag();
			setCurPoint(pos);
			scrollLayout.snapToScreen(pos);
		}
		if (v.getId()==c_backView.getId()) {
			
			finish();
		}
		
		System.out.println("click"+v.getId());
	}
	
	private SimpleAdapter getMeunAdapter()
	{
		ArrayList<HashMap<String, Object>> list = new ArrayList<HashMap<String,Object>>();
		for (int i = 0; i < 12; i++) {
			HashMap<String, Object> map = new HashMap<String, Object>();
			map.put("itemimage", R.drawable.seat_normal);
			map.put("itemtext", "第"+(i+1)+"桌");
			list.add(map);
		}
		
		SimpleAdapter adapter = new SimpleAdapter(ChooseTableActivity.this, list, R.layout.griditem, 
				new String[]{"itemimage","itemtext"},
				new int[]{R.id.item_image,R.id.item_text});
		return adapter;
		
	}

	@Override
	public void onItemClick(AdapterView<?> arg0, View v, int loc, long arg3) {
		// TODO Auto-generated method stub
		int whichfloat =49;
		whichfloat = c_tagView.getText().charAt(0)-48;
		System.out.println(whichfloat+"楼"+(loc+1)+"桌");
		
		
	}
	

}

GridView 的Adapter跟ListView 的比较相似,都要创建两个layout文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
	
    <ImageView 
        android:id="@+id/item_image"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:contentDescription="@null"
        />
    <TextView 
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/item_image"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        />

</RelativeLayout>

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
     >
    <!-- 用来加载Item -->
    <com.lin.helper.MyGridView 
        android:id="@+id/gridview_only"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:columnWidth="90dp"
        android:gravity="center"
        android:numColumns="auto_fit"
        android:horizontalSpacing="10dp"
        android:verticalSpacing="10dp"
        android:stretchMode="columnWidth"
        
        ></com.lin.helper.MyGridView>

</LinearLayout>


差不多这样啦,上面的MyscrollLayout其实还自定义了一个onViewChangeListerner()接口


内容概要:本文针对考虑算力负荷时空迁移特性的多微电网与共享储能系统的协同优化调度问题展开研究,并提供了完整的Matlab代码实现。研究构建了融合算力负荷动态迁移特征的数学优化模型,通过引入共享储能机制,实现多微电网间的能量互济与资源协同,有效提升系统对分布式能源波动性和负荷不确定性的适应能力。文中采用先进的优化算法求解该调度模型,重点解决了算力任务在时空维度上的灵活调配与电力供需平衡之间的耦合关系,旨在提高综合能源系统的运行经济性、可靠性与灵活性。所提出的方法为未来能源互联网背景下电-算协同管理提供了理论支持与技术路径。; 适合人群:具备电力系统分析、优化理论基础及Matlab编程能力的科研人员、高校研究生,尤其适用于从事微电网运行、共享储能配置、综合能源系统优化以及电-算融合等领域研究的专业技术人员。; 使用场景及目标:①开展多微电网与共享储能系统的协同调度策略设计与仿真验证;②支撑高比例可再生能源接入下的新型电力系统优化运行研究;③为考虑算力迁移的数据中心与电网协同调度提供建模与算法参考;④作为高水平学术论文撰写或学位课题研究的技术支撑与代码复现平台。; 阅读建议:建议读者结合Matlab代码与相关学术文献深入研读,重点关注目标函数构建、约束条件设定及求解器调用逻辑,可在现有模型基础上拓展多时间尺度优化、不确定性建模(如鲁棒优化、随机规划)或加入实际工程约束进行二次开发与深化研究。
内容概要:本文围绕“双层优化”方法在电动汽车有序充电中的应用展开研究,重点探讨了如何通过Matlab代码实现面向智能电网背景下的电动汽车充电优化调度。文中提出了一种双层优化模型,上层以系统运行成本最小化为目标进行全局优化,下层则综合考虑用户充电需求、行为特性及响应意愿,实现有序充电策略的局部优化。该模型充分结合实际电力系统约束条件,如配电网容量限制、分时电价机制以及可再生能源出力波动等,有效提升了充电管理的经济性、稳定性和可实施性。研究还提供了完整的Matlab代码实现方案,并配套YALMIP、CPLEX等工具的调用示例,便于读者复现算法与仿真流程。此外,文档列举了多个相关科研方向与仿真资源,涵盖微电网优化、智能算法调度、电动汽车与储能协同控制等领域,并附有网盘资料下载链接,支持进一步拓展研究。; 适合人群:具备一定电力系统基础知识和优化算法理解能力,从事新能源、智能电网、电动汽车等领域研究的研究生、高校科研人员及工程技术人员。; 使用场景及目标:①学习并掌握双层优化模型在电动汽车有序充电场景中的建模思路与求解方法;②利用Matlab实现电力系统中复杂的多目标、多层次优化调度问题;③复现高水平期刊论文中的优化策略,支撑科研项目申报、学术论文撰写或学位课题研究。; 阅读建议:建议结合所提供的Matlab代码与建模框架进行动手实践,重点关注双层架构的数学建模过程与上下层交互机制,熟练掌握YALMIP建模语言和CPLEX求解器的使用技巧,同时参考文档中推荐的相关研究方向开展横向对比与创新延伸。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值