2014-10-27 Android learning ------ layout processing ------ custom Toast ------ city list application

I study Android in combination with the source code, which is more intuitive and very clear to see the effect. I think it's very good. Today's learning source code is a CityList source code found online. Baidu search knows a lot of places to download

Last article address: http://blog.csdn.net/u014737138/article/details/40589131

Sometimes we need to prompt a small box on the view, and a prompt pops up on it

Let's see the effect first:

For example, the blue large D in the figure

What we need to implement is such a custom Toast

How to deal with the layout file:

code:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#ffffff "background white
    android:gravity="center"
    android:maxWidth="80dip"
    android:minWidth="80dip"
    android:padding="5dip"
    android:textColor="#3399ff "blue font
    android:textSize="70sp" />   Font size is 70 sp

Effects in Eclipse:

That's it. Then we need to use it and see how it works:

1. Declare in activity:

private TextView overlay;

2. When initializing, we need to find this control from the resource file

	private void initOverlay()
	{
		LayoutInflater inflater = LayoutInflater.from(this);
		overlay = (TextView) inflater.inflate(R.layout.overlay, null);
		overlay.setVisibility(View.INVISIBLE);
		WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
				WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
				PixelFormat.TRANSLUCENT);
		WindowManager windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
		windowManager.addView(overlay, lp);
	}

When customizing this toast, we didn't set its width and height. The picture above suggests that we didn't set its width and height. Originally, we need to set it in this position.

import android.view.WindowManager;

Here I find out the meaning of these variables from the Android document. Let's see what this variable means:

Corresponding to this sentence:

WindowManager windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);

this refers to the context of the current activity,

Corresponding to this sentence:

windowManager.addView(overlay, lp);

These two parameters are easy to explain: any widget in Android can be regarded as a View object, including custom

Then the next step is to write out the object corresponding to lp. The type of lp is: ViewGroup LayoutParams

The previous figure shows me that WindowManager implements ViewManager,

The following figure shows WindowManager Layoutparams implements ViewGroup Of layoutparams

The following figure shows us his constructor:

That's the box we choose

The next step is to see what the parameters mean:

That's it.

To put it bluntly, this initialization function is to add a view on the current form: this view is our custom Toast

Here also tells us one thing: if we want to implement a method, it is most appropriate to find what we need from the Android documents. If anyone is proficient in the Android documents, it must be the bull of the bull!!!!!

3. When using it

overlay.setText(sections[position]);// Set text overlay.setVisibility(View.VISIBLE);// Set visible

In this way, we can simply finish the effect, but at this time, someone must say, how do you display it like the Toast provided by the system and it will disappear automatically after a while,

This is also simple. We need to do a display time processing. Define a thread to solve this problem

Step 1:

First, define a thread class with the name of this control to implement the Runable interface

//Set overlay invisible private class OverlayThread implements Runnable { @Override public void run() { overlay.setVisibility(View.GONE); } }

int android.view.View.GONE = 8 [0x8]



public static final int GONE 
Since: API Level 1 
This view is invisible, and it doesn't take any space for layout purposes. Use with setVisibility(int). 

To put it bluntly, overload the run() function to make this control invisible. The benefits of using the go variable are as follows:

INVISIBLE: it still takes up space, but the content is not displayed. GONE: it will not take up space.

Here we also know that a small toast is displayed on the current view. Is the message (UI) update executed by the current activity main thread or by the sub thread?

Generally speaking, the function of updating the view in Android is executed by the main thread, but its execution interval is quite short, as if it is only 6 seconds. If it exceeds this time, the application will have an anr exception. Generally, we use the sub thread to process this message. After processing, we tell the main thread to update it.

What you said is not very right. If not, please point it out. Still learning!!!

So we use the sub thread to be responsible for the time it displays,

How can the thread created by itself call them? Here we need to use a class Handler

Let's briefly explain it first: you can understand it if you know what it does. Next time, you will have a chance to introduce its usage and function in detail

Handler is very commonly used in Android. It can be used to update the UI, or send tasks to sub threads for execution. It can also be used to produce timeout effects, such as sendMessageDelayed(TASK_TIMEOUT, OUT_TIME) method

Don't say anything superfluous. Just look at the code and make it clearer:

1. Define a Handler object in the activity

private Handler handler;

2. Initialization

handler = new Handler();

3. Use

handler.removeCallbacks(overlayThread);
// Delay the execution for one second and make the overlay invisible
handler.postDelayed(overlayThread, 1500);

The source code of this function is all:

	private class LetterListViewListener implements OnTouchingLetterChangedListener
	{

		@Override
		public void onTouchingLetterChanged(final String s)
		{
			if (alphaIndexer.get(s) != null)
			{
				int position = alphaIndexer.get(s);
				mCityLit.setSelection(position);
				overlay.setText(sections[position]);
				overlay.setVisibility(View.VISIBLE);
				handler.removeCallbacks(overlayThread);
				// Execute after a delay of 1.5 seconds to make the overlay invisible
				handler.postDelayed(overlayThread, 1500);
			}
		}

	}

Here I want to say: what is the difference between the postDelayed method and the removeCallbacks method? Why is this set here? What role do they play?

Method removeCallbacks is to delete the specified Runnable object and stop the thread object: first, why do we stop the thread? When we touch a letter inside the class, it is possible that we need to touch it first,

The function of the postDelayed method is to delay how many milliseconds before starting to run: the function is to delay the execution of this thread by 1.5 seconds, that is, my control displays for 1.5 seconds first, and then the sub thread tells me that this control cannot be displayed.

Its prototype:

 public final boolean postDelayed (Runnable r, long delayMillis) 

The parameter Runnable r is executed in the thread in which the Handler object runs. So far, this custom toast is basically introduced from creation to use. Its source code:

public class CityList extends Activity {
	
	private BaseAdapter adapter;
	private ListView mCityLit;
	private TextView overlay;
	private MyLetterListView letterListView;
	private HashMap<String, Integer> alphaIndexer;// Store the existing Chinese pinyin initials and their corresponding list positions
	private String[] sections;// Stored Chinese pinyin initials
	private Handler handler;
	private OverlayThread overlayThread;
	private SQLiteDatabase database;
	private ArrayList<CityModel> mCityNames;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.city_list);
		
		mCityLit = (ListView) findViewById(R.id.city_list);
		letterListView = (MyLetterListView) findViewById(R.id.cityLetterListView);
		DBManager dbManager = new DBManager(this);
		dbManager.openDateBase();
		dbManager.closeDatabase();
		database = SQLiteDatabase.openOrCreateDatabase(DBManager.DB_PATH + "/" + DBManager.DB_NAME, null);
		mCityNames = getCityNames();
		database.close();
		letterListView.setOnTouchingLetterChangedListener(new LetterListViewListener());
		alphaIndexer = new HashMap<String, Integer>();
		handler = new Handler();
		overlayThread = new OverlayThread();
		initOverlay();
		setAdapter(mCityNames);
		mCityLit.setOnItemClickListener(new CityListOnItemClick());
	}
	
	/**
	 * Get city data from database
	 * 
	 * @return
	 */
	private ArrayList<CityModel> getCityNames()
	{
		ArrayList<CityModel> names = new ArrayList<CityModel>();
		Cursor cursor = database.rawQuery("SELECT * FROM T_City ORDER BY NameSort", null);
		for (int i = 0; i < cursor.getCount(); i++)
		{
			cursor.moveToPosition(i);
			CityModel cityModel = new CityModel();
			cityModel.setCityName(cursor.getString(cursor.getColumnIndex("CityName")));
			cityModel.setNameSort(cursor.getString(cursor.getColumnIndex("NameSort")));
			names.add(cityModel);
		}
		return names;
	}
	
	/**
	 * City list click event
	 * 
	 * @author sy
	 * 
	 */
	class CityListOnItemClick implements OnItemClickListener
	{

		@Override
		public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3)
		{
			CityModel cityModel = (CityModel) mCityLit.getAdapter().getItem(pos);
			Toast.makeText(CityList.this, cityModel.getCityName(), Toast.LENGTH_SHORT).show();
		}

	}
	
	/**
	 * Set adapter for ListView
	 * 
	 * @param list
	 */
	private void setAdapter(List<CityModel> list)
	{
		if (list != null)
		{
			adapter = new ListAdapter(this, list);
			mCityLit.setAdapter(adapter);
		}

	}
	
	/**
	 * ListViewAdapter
	 * 
	 * @author sy
	 * 
	 */
	private class ListAdapter extends BaseAdapter
	{
		private LayoutInflater inflater;
		private List<CityModel> list;

		public ListAdapter(Context context, List<CityModel> list)
		{

			this.inflater = LayoutInflater.from(context);
			this.list = list;
			alphaIndexer = new HashMap<String, Integer>();
			sections = new String[list.size()];

			for (int i = 0; i < list.size(); i++)
			{
				// Current Pinyin initials
				// getAlpha(list.get(i));
				String currentStr = list.get(i).getNameSort();
				// The first letter of the previous Chinese pinyin. If it does not exist, it is ""
				String previewStr = (i - 1) >= 0 ? list.get(i - 1).getNameSort() : " ";
				if (!previewStr.equals(currentStr))
				{
					String name = list.get(i).getNameSort();
					alphaIndexer.put(name, i);
					sections[i] = name;
				}
			}

		}

		@Override
		public int getCount()
		{
			return list.size();
		}

		@Override
		public Object getItem(int position)
		{
			return list.get(position);
		}

		@Override
		public long getItemId(int position)
		{
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent)
		{
			ViewHolder holder;
			if (convertView == null)
			{
				convertView = inflater.inflate(R.layout.list_item, null);
				holder = new ViewHolder();
				holder.alpha = (TextView) convertView.findViewById(R.id.alpha);
				holder.name = (TextView) convertView.findViewById(R.id.name);
				convertView.setTag(holder);
			} else
			{
				holder = (ViewHolder) convertView.getTag();
			}

			holder.name.setText(list.get(position).getCityName());
			String currentStr = list.get(position).getNameSort();
			String previewStr = (position - 1) >= 0 ? list.get(position - 1).getNameSort() : " ";
			if (!previewStr.equals(currentStr))
			{
				holder.alpha.setVisibility(View.VISIBLE);
				holder.alpha.setText(currentStr);
			} else
			{
				holder.alpha.setVisibility(View.GONE);
			}
			return convertView;
		}

		private class ViewHolder
		{
			TextView alpha;
			TextView name;
		}

	}
	
	// Pop up prompt box for initializing the first letter of Chinese Pinyin
	private void initOverlay()
	{
		LayoutInflater inflater = LayoutInflater.from(this);
		overlay = (TextView) inflater.inflate(R.layout.overlay, null);
		overlay.setVisibility(View.INVISIBLE);
		WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
				WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
				PixelFormat.TRANSLUCENT);
		WindowManager windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
		windowManager.addView(overlay, lp);
	}
	
	private class LetterListViewListener implements OnTouchingLetterChangedListener
	{

		@Override
		public void onTouchingLetterChanged(final String s)
		{
			if (alphaIndexer.get(s) != null)
			{
				int position = alphaIndexer.get(s);
				mCityLit.setSelection(position);
				overlay.setText(sections[position]);
				overlay.setVisibility(View.VISIBLE);
				handler.removeCallbacks(overlayThread);
				// Delay the execution for one second and make the overlay invisible
				handler.postDelayed(overlayThread, 1500);
			}
		}

	}
	
	// Set overlay invisible
	private class OverlayThread implements Runnable
	{

		@Override
		public void run()
		{
			overlay.setVisibility(View.GONE);
		}

	}
	
	

}

Added by jacomus on Mon, 07 Mar 2022 03:45:14 +0200