編輯:關於Android編程
UI效果圖:
最終的效果是可以滑動刻度來選取金額,並且滑動停止後必須定位到某個金額上,不能停留在中間。
分析:決定用listview來實現上述效果
分析UI圖,發現有三種類型的item,短的,長的,還有長的帶文字的。
1.listview所用的adapter的實現。
ListAdaptera.java文件
package com.miduo.financialmanageclient.ui.adapter; import java.util.List; import android.content.Context; import android.content.ClipData.Item; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.miduo.financialmanageclient.R; /** * 立即投資頁面刻度 本來覺得不用復用了,結果發現會卡死,還是得復用 * * @author huozhenpeng * */ public class ListAdaptera extends BaseAdapter { private Context context; private Listlists; private static final int TYPE_ITEM_FIRST = 0; private static final int TYPE_ITEM_SECOND = 1; private static final int TYPE_ITEM_THREE = 2; public ListAdaptera(Context context, List lists) { this.context = context; this.lists = lists; } @Override public int getCount() { return lists.size(); } @Override public Object getItem(int position) { return lists.get(position); } @Override public long getItemId(int position) { return position; } @Override public int getItemViewType(int position) { if (position == 0 || position % 10 == 0) { return TYPE_ITEM_FIRST; } else if (position % 5 == 0) { return TYPE_ITEM_SECOND; } else { return TYPE_ITEM_THREE; } } @Override public int getViewTypeCount() { return 3; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; int type = getItemViewType(position); if (convertView == null) { switch (type) { case TYPE_ITEM_FIRST: viewHolder = new ViewHolder(); convertView = LayoutInflater.from(context).inflate( R.layout.item_list, null); viewHolder.tv_left = ((TextView) convertView .findViewById(R.id.tv_left)); viewHolder.tv_right = ((TextView) convertView .findViewById(R.id.tv_right)); convertView.setTag(viewHolder); break; case TYPE_ITEM_SECOND: convertView = LayoutInflater.from(context).inflate( R.layout.item_list3, null); break; case TYPE_ITEM_THREE: convertView = LayoutInflater.from(context).inflate( R.layout.item_list2, null); break; default: break; } } switch (type) { case TYPE_ITEM_FIRST: viewHolder = (ViewHolder) convertView.getTag(); viewHolder.tv_left.setText(lists.get(position) + "萬"); viewHolder.tv_right.setText(lists.get(position) + "萬"); break; case TYPE_ITEM_SECOND: break; case TYPE_ITEM_THREE: break; default: break; } return convertView; } final static class ViewHolder { TextView tv_left, tv_right; } }
item_list.xml文件
item_list2.xml文件
注意:1.剛剛開始覺得布局文件比較簡單,沒有必要復用,後來發現如果計算出來的刻度特別多滑動又比較快會卡死。
2.適配方式采用等比例適配。(就是說在720的手機上大小是72px的換到1080的手機上則占108px)。
先粘貼上全部代碼,再對代碼進行分析
MainActivityt.java類
package com.example.wavedemo; import java.util.ArrayList; import java.util.List; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.graphics.Color; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; public class MainActivityt extends Activity { private ListView listview; private Listlists = new ArrayList (); private ListAdaptera adapter; private int position; private int top; private int itemHeight; private int height; private int deltaItemNum;// 差距條數 private int remainder;// 余數 // 全部以萬為單位 private int startMoney = 5;// 起投金額 private int deltaMoney = 1;// 遞增金額 private int canInvestMoney = 1097;// 可投金額 // 補一個頭部 private LinearLayout ll_head; // 補一個footer private LinearLayout ll_footer; // 靜止之後實際的position private int actualPosition; @TargetApi(19) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_maint); itemHeight = (int) getResources().getDimension(R.dimen.px2dp_26); height = (int) getResources().getDimension(R.dimen.px2dp_544); initHead(); initFooter(); // 算出總共有多少個實際的格子(可以滑動到中間位置上的) for (int i = startMoney; i <= canInvestMoney; i += deltaMoney) { lists.add(i); } adapter = new ListAdaptera(this, lists); listview = (ListView) this.findViewById(R.id.listview); listview.addHeaderView(ll_head); listview.addFooterView(ll_footer); listview.setAdapter(adapter); listview.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, long id) { } @Override public void onNothingSelected(AdapterView parent) { } }); listview.setOnScrollListener(new OnScrollListener() { @SuppressLint("NewApi") @Override public void onScrollStateChanged(AbsListView view, int scrollState) { switch (scrollState) { case SCROLL_STATE_FLING:// 手指離開屏幕後,慣性滑動 break; case SCROLL_STATE_IDLE:// 滑動後靜止 position = listview.getFirstVisiblePosition();// 第幾個item top = getViewByPosition(position, listview).getTop(); if (position == 0) { if (top == 0 || -top <= itemHeight / 2)// 定位到起投金額 { listview.setSelectionFromTop(1, (height - itemHeight) / 2); actualPosition = 0; } else { listview.setSelectionFromTop( -(top + itemHeight / 2) / itemHeight + 2, (height - itemHeight) / 2); actualPosition = -(top + itemHeight / 2) / itemHeight + 1; } } else { deltaItemNum = (height / 2 - (itemHeight + top)) / itemHeight; listview.setSelectionFromTop(position + deltaItemNum + 1, (height - itemHeight) / 2); actualPosition = position + deltaItemNum; } MToast.showToast(MainActivityt.this, lists.get(actualPosition) + "萬"); showHighLight(actualPosition, listview); break; case SCROLL_STATE_TOUCH_SCROLL:// 手指在屏幕上滑動 break; default: break; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { return true; } public View getViewByPosition(int pos, ListView listView) { final int firstListItemPosition = listView.getFirstVisiblePosition(); final int lastListItemPosition = firstListItemPosition + listView.getChildCount() - 1; if (pos < firstListItemPosition || pos > lastListItemPosition) { return listView.getAdapter().getView(pos, null, listView); } else { final int childIndex = pos - firstListItemPosition; return listView.getChildAt(childIndex); } } /** * 添加輔助頭部 */ private void initHead() { ll_head = new LinearLayout(this); ll_head.setOrientation(LinearLayout.VERTICAL); AbsListView.LayoutParams params = new AbsListView.LayoutParams( AbsListView.LayoutParams.MATCH_PARENT, (height - itemHeight) / 2); ll_head.setLayoutParams(params); ll_head.addView(new View(this), 0, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, itemHeight / 2)); int total = (height - itemHeight) / 2 / itemHeight + 1; View view = null; for (int i = 1; i <= total; i++) { if (i % 5 == 0) { view = LayoutInflater.from(this).inflate(R.layout.item_list3, null); } else { view = LayoutInflater.from(this).inflate(R.layout.item_list2, null); } ll_head.addView(view, 0); } } /** * 添加輔助頭部 */ private void initFooter() { ll_footer = new LinearLayout(this); ll_footer.setOrientation(LinearLayout.VERTICAL); AbsListView.LayoutParams params = new AbsListView.LayoutParams( AbsListView.LayoutParams.MATCH_PARENT, (height - itemHeight) / 2); ll_footer.setLayoutParams(params); ll_footer.addView(new View(this), 0, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, itemHeight / 2)); int total = (height - itemHeight) / 2 / itemHeight + 1; View view = null; for (int i = 1; i <= total; i++) { view = LayoutInflater.from(this).inflate(R.layout.item_list2, null); ll_footer.addView(view, 0); } } private void showHighLight(int pos, ListView listview) { View view = getViewByPosition(pos + 1, listview); TextView tv_left = (TextView) view.findViewById(R.id.tv_left); TextView tv_right = (TextView) view.findViewById(R.id.tv_right); if (tv_left != null) { tv_left.setTextColor(Color.parseColor("#fe7800")); tv_right.setTextColor(Color.parseColor("#fe7800")); } } }
代碼分析:
定義listview每個item的高度
itemHeight = (int) getResources().getDimension(R.dimen.px2dp_26);
定義listview的總高度
height = (int) getResources().getDimension(R.dimen.px2dp_544);
初始化listview頭部
initHead(); 初始化listview腳部
initFooter();為什麼要給listview添加頭部和腳部呢,
首先在剛剛進入頁面的時候必須保證起投金額位於位於listview的正中間,此時listview可以向下滑動但是不能向上滑動,所以為了保證起投金額(5萬,是adapter數據源(集合)中的第一個數據)位於listview正中間,需要給listview添加個頭部,所以5萬以上展現出來的效果其實是listview的一個頭部。
代碼中:
/** * 添加輔助頭部 */ private void initHead() { ll_head = new LinearLayout(this); ll_head.setOrientation(LinearLayout.VERTICAL); AbsListView.LayoutParams params = new AbsListView.LayoutParams( AbsListView.LayoutParams.MATCH_PARENT, (height - itemHeight) / 2); ll_head.setLayoutParams(params); ll_head.addView(new View(this), 0, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, itemHeight / 2)); int total = (height - itemHeight) / 2 / itemHeight + 1; View view = null; for (int i = 1; i <= total; i++) { if (i % 5 == 0) { view = LayoutInflater.from(this).inflate(R.layout.item_list3, null); } else { view = LayoutInflater.from(this).inflate(R.layout.item_list2, null); } ll_head.addView(view, 0); } }
首先需要知道一個item的范圍是多少:
青色框框住的部分是每個item的范圍。相當於是每個刻度線在整個item內是居中顯示的。
所以在計算頭部高度的時候
AbsListView.LayoutParams params = new AbsListView.LayoutParams( AbsListView.LayoutParams.MATCH_PARENT, (height - itemHeight) / 2);
這裡首先添加了半個item的高度,這半個item相當於是5萬的那半個
ll_head.addView(new View(this), 0, new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, itemHeight / 2));
然後計算出剩余部分所需的item條數
int total = (height - itemHeight) / 2 / itemHeight + 1;
由於整形計算會捨棄精度,所以最後加上1
添加listview腳部也是相同的原理,為了能使最大額度(1097)滑到listview中間,所以需要加入腳部,腳部的代碼比較簡單,不做分析。
核心代碼:
case SCROLL_STATE_IDLE:// 滑動後靜止 position = listview.getFirstVisiblePosition();// 第幾個item top = getViewByPosition(position, listview).getTop(); if (position == 0) { if (top == 0 || -top <= itemHeight / 2)// 定位到起投金額 { listview.setSelectionFromTop(1, (height - itemHeight) / 2); actualPosition = 0; } else { listview.setSelectionFromTop( -(top + itemHeight / 2) / itemHeight + 2, (height - itemHeight) / 2); actualPosition = -(top + itemHeight / 2) / itemHeight + 1; } } else { deltaItemNum = (height / 2 - (itemHeight + top)) / itemHeight; listview.setSelectionFromTop(position + deltaItemNum + 1, (height - itemHeight) / 2); actualPosition = position + deltaItemNum; } MToast.showToast(MainActivityt.this, lists.get(actualPosition) + "萬"); showHighLight(actualPosition, listview); break;
position = listview.getFirstVisiblePosition();// 第幾個item這條代碼比較簡單,就是第一個可見的item,從0到很大
top = getViewByPosition(position, listview).getTop();得到每個item的top值(Top position of this view relative to its parent.)
然後判斷position是不是等於0,等於0說明起投金額(5萬)還沒有劃出屏幕,這段代碼的意思是應該滑動靜止後應該定位到起投金額,
actualPosition是完全靜止後實際的position,記錄下來從集合中取數據用。
top==0是初始狀態下,向下拖拽listview的情況
-top <= itemHeight / 2是向上拽,但是距離小於item一半的高度
setSelectionFromTop(int position,int y)
@param position Index (starting at 0) of the data item to be selected.
@param y The distance from the top edge of the ListView (plus padding) that the
item will be positioned.
也就是說position是要被選中的item,從0開始,y是距離被選中的item的高度,代碼中寫的1,是因為listview加了頭部,頭部算0位置。(height - itemHeight) / 2)是listview頭部的高度,就是說第一個item距離頂部的距離為
(height - itemHeight) / 2
if (top == 0 || -top <= itemHeight / 2)// 定位到起投金額 { listview.setSelectionFromTop(1, (height - itemHeight) / 2); actualPosition = 0; }
在向下滑動時,top一直為負值,並不斷減小(-1,-2,-3,................)
-(top + itemHeight / 2)
這裡的itemHeight/2是起投哪個item的下半截高度
else { listview.setSelectionFromTop( -(top + itemHeight / 2) / itemHeight + 2, (height - itemHeight) / 2); actualPosition = -(top + itemHeight / 2) / itemHeight + 1; }
---------------------------------分割線-------------------------------------------------分割線--------------------------------------------------分割線------------------------
分析另一種情況
這種情況下的top的絕對值肯定會小於itemHeight的值
else { deltaItemNum = (height / 2 - (itemHeight + top)) / itemHeight; listview.setSelectionFromTop(position + deltaItemNum + 1, (height - itemHeight) / 2); actualPosition = position + deltaItemNum; }
以前寫過一篇ViewPager:內容content+指示點的Demo; 這篇文章繼續介紹ViewPager:內容content+標題title的Demo。
顯示對話框窗口 1、創建Dialog1項目,在activity_main.xml文件中添加一個Button: 2、在MainActivity.jav
Android開放的平台,獲得高度自由度,用戶也要承受系統當中一些潛在的問題,比如後台流量的消耗。那麼怎樣才能有效控制Android的流量使用呢?下面這5個
之前在三星手機上看到點擊屏幕後出現水波的特效,所以嘗試著寫了個類似的效果 實現自定義一個View,並實現構造方法public class MyView exte