当前位置:  编程技术>移动开发
本页文章导读:
    ▪几种惯用控件的使用方法        几种常用控件的使用方法1.UIActivityIndicatorView的使用  UIActivityIndicatorView *activity=[[[UIActivityIndicatorViewalloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]autorelease]; z     [activity setFrame:CGRectMa.........
    ▪ 文件行列 QueueFile        文件队列 QueueFile/** * Copyright (C) 2010 Square, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * htt.........
    ▪ 元件之间图标拖拽       部件之间图标拖拽又到周末了,尝试实现一个图标拖拽的小程序;主要实现的功能有: 1.两个部件的图标拖动转移 2.可以切换图标查看模式,有大图标和小图标模式两种 3.可以删除图标,添.........

[1]几种惯用控件的使用方法
    来源: 互联网  发布时间: 2014-02-18
几种常用控件的使用方法

1.UIActivityIndicatorView的使用

 UIActivityIndicatorView *activity=[[[UIActivityIndicatorViewalloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]autorelease];

z

    [activity setFrame:CGRectMake(150,150, 50, 50)];

    [self.window addSubview:activity];    

    [activity startAnimating];

2. UISlider的使用

    UISlider *slider=[[[UISlideralloc] initWithFrame:CGRectMake(100,20, 140,20)] autorelease];

    slider.maximumValue=10;

    slider.value=5;

    [slider addTarget:selfaction:@selector(change:)forControlEvents:UIControlEventTouchUpInside];

    [self.window addSubview:slider];

-(void)change:(UISlider*)slider

{

    NSLog(@"the val is %.2f",slider.value);

}

3.UIPageControl

通常与UIScrollView连用,提示用户当前显示的页数

@property(nonatomic) NSInteger numberOfPages;          // default is 0

@property(nonatomic) NSInteger currentPage;            // default is 0. value pinned to 0..numberOfPages-1

@property(nonatomic) BOOL hidesForSinglePage;          // hide the the indicator if there is only one page. default is NO

sample code:

 UIPageControl *pageControl=[[[UIPageControl alloc] initWithFrame:CGRectMake(0, 50, 329, 30)] autorelease];
    pageControl.numberOfPages=10;
    pageControl.currentPage=3;
    pageControl.backgroundColor=[UIColor grayColor];
    [pageControl addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventValueChanged];
    [self.window addSubview:pageControl];
-(void)clicked:(id)sender
{
    UIPageControl *pageControl=(UIPageControl*)sender;
    NSLog(@"curent val is %d",pageControl.currentPage);
}

4.UISegmentedControl

  NSArray *array=[NSArray arrayWithObjects:@"hello",@"what",@"search",nil];
    UISegmentedControl *segmentControl=[[[UISegmentedControl alloc] initWithItems:array] autorelease];
    segmentControl.frame=CGRectMake(0, 40, 300, 40);
    segmentControl.segmentedControlStyle=UISegmentedControlStyleBordered;
    segmentControl.selectedSegmentIndex=2;
    [segmentControl addTarget:self action:@selector(clicked:) forControlEvents:UIControlEventValueChanged];
    [self.window addSubview:segmentControl];




    
[2] 文件行列 QueueFile
    来源: 互联网  发布时间: 2014-02-18
文件队列 QueueFile
/**
 * Copyright (C) 2010 Square, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.squareup.util;
 
import com.squareup.Square;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileChannel;
import java.util.NoSuchElementException;
 
/**
 * A reliable, efficient, file-based, FIFO queue. Additions and removals are
 * O(1). All operations are atomic. Writes are synchronous; data will be
 * written to disk before an operation returns. The underlying file is
 * structured to survive process and even system crashes. If an I/O exception
 * is thrown during a mutating change, the change is aborted. It is safe to
 * continue to use a {@code QueueFile} instance after an exception.
 *
 * <p>All operations are synchronized. In a traditional queue, the remove
 * operation returns an element. In this queue, {@link #peek} and {@link
 * #remove} are used in conjunction. Use {@code peek} to retrieve the first
 * element, and then {@code remove} to remove it after successful processing.
 * If the system crashes after {@code peek} and during processing, the element
 * will remain in the queue, to be processed when the system restarts.
 *
 * <p><b><font color="red">NOTE:</font></b> The current implementation is
 * built for file systems that support atomic segment writes (like YAFFS).
 * Most conventional file systems don't support this; if the power goes out
 * while writing a segment, the segment will contain garbage and the file will
 * be corrupt. We'll add journaling support so this class can be used with
 * more file systems later.
 *
 * @author Bob Lee (bob@squareup.com)
 */
public class QueueFile {
 
/** Initial file size in bytes. */
private static final int INITIAL_LENGTH = 4096; // one file system block
 
/** Length of header in bytes. */
static final int HEADER_LENGTH = 16;
 
/**
  * The underlying file. Uses a ring buffer to store entries. Designed so
  * that a modification isn't committed or visible until we write the header.
  * The header is much smaller than a segment. So long as the underlying file
  * system supports atomic segment writes, changes to the queue are atomic.
  * Storing the file length ensures we can recover from a failed expansion
  * (i.e. if setting the file length succeeds but the process dies before the
  * data can be copied).
  *
  * <pre>
  * Format:
  * Header (16 bytes)
  * Element Ring Buffer (File Length - 16 bytes)
  *
  * Header:
  * File Length (4 bytes)
  * Element Count (4 bytes)
  * First Element Position (4 bytes, =0 if null)
  * Last Element Position (4 bytes, =0 if null)
  *
  * Element:
  * Length (4 bytes)
  * Data (Length bytes)
  * </pre>
  */
private final RandomAccessFile raf;
 
/** Cached file length. Always a power of 2. */
int fileLength;
 
/** Number of elements. */
private int elementCount;
 
/** Pointer to first (or eldest) element. */
private Element first;
 
/** Pointer to last (or newest) element. */
private Element last;
 
/** In-memory buffer. Big enough to hold the header. */
private final byte[] buffer = new byte[16];
 
/**
  * Constructs a new queue backed by the given file. Only one {@code QueueFile}
  * instance should access a given file at a time.
  */
public QueueFile(File file) throws IOException {
if (!file.exists()) initialize(file);
raf = open(file);
readHeader();
}
 
/** For testing. */
QueueFile(RandomAccessFile raf) throws IOException {
this.raf = raf;
readHeader();
}
 
/**
  * Stores int in buffer. The behavior is equivalent to calling
  * {@link RandomAccessFile#writeInt}.
  */
private static void writeInt(byte[] buffer, int offset, int value) {
buffer[offset] = (byte) (value >> 24);
buffer[offset + 1] = (byte) (value >> 16);
buffer[offset + 2] = (byte) (value >> 8);
buffer[offset + 3] = (byte) value;
}
 
/**
  * Stores int values in buffer. The behavior is equivalent to calling
  * {@link RandomAccessFile#writeInt} for each value.
  */
private static void writeInts(byte[] buffer, int... values) {
int offset = 0;
for (int value : values) {
writeInt(buffer, offset, value);
offset += 4;
}
}
 
/**
  * Reads an int from a byte[].
  */
private static int readInt(byte[] buffer, int offset) {
return ((buffer[offset] & 0xff) << 24)
+ ((buffer[offset + 1] & 0xff) << 16)
+ ((buffer[offset + 2] & 0xff) << 8)
+ (buffer[offset + 3] & 0xff);
}
 
/**
  * Reads the header.
  */
private void readHeader() throws IOException {
raf.seek(0);
raf.readFully(buffer);
fileLength = readInt(buffer, 0);
elementCount = readInt(buffer, 4);
int firstOffset = readInt(buffer, 8);
int lastOffset = readInt(buffer, 12);
first = readElement(firstOffset);
last = readElement(lastOffset);
}
 
/**
  * Writes header atomically. The arguments contain the updated values. The
  * class member fields should not have changed yet. This only updates the
  * state in the file. It's up to the caller to update the class member
  * variables *after* this call succeeds. Assumes segment writes are atomic
  * in the underlying file system.
  */
private void writeHeader(int fileLength, int elementCount, int firstPosition,
int lastPosition) throws IOException {
writeInts(buffer, fileLength, elementCount, firstPosition, lastPosition);
raf.seek(0);
raf.write(buffer);
}
 
/**
  * Returns the Element for the given offset.
  */
private Element readElement(int position) throws IOException {
if (position == 0) return Element.NULL;
raf.seek(position);
return new Element(position, raf.readInt());
}
 
/** Atomically initializes a new file. */
private static void initialize(File file) throws IOException {
// Use a temp file so we don't leave a partially-initialized file.
File tempFile = new File(file.getPath() + ".tmp");
RandomAccessFile raf = open(tempFile);
try {
raf.setLength(INITIAL_LENGTH);
raf.seek(0);
byte[] headerBuffer = new byte[16];
writeInts(headerBuffer, INITIAL_LENGTH, 0, 0, 0);
raf.write(headerBuffer);
} finally {
raf.close();
}
 
// A rename is atomic.
if (!tempFile.renameTo(file)) throw new IOException("Rename failed!");
}
 
/**
  * Opens a random access file that writes synchronously.
  */
private static RandomAccessFile open(File file) throws FileNotFoundException {
return new RandomAccessFile(file, "rwd");
}
 
/**
  * Wraps the position if it exceeds the end of the file.
  */
private int wrapPosition(int position) {
return position < fileLength ? position
: HEADER_LENGTH + position - fileLength;
}
 
/**
  * Writes count bytes from buffer to position in file. Automatically wraps
  * write if position is past the end of the file or if buffer overlaps it.
  *
  * @param position in file to write to
  * @param buffer to write from
  * @param count # of bytes to write
  */
private void ringWrite(int position, byte[] buffer, int offset, int count)
throws IOException {
position = wrapPosition(position);
if (position + count <= fileLength) {
raf.seek(position);
raf.write(buffer, offset, count);
} else {
// The write overlaps the EOF.
// # of bytes to write before the EOF.
int beforeEof = fileLength - position;
raf.seek(position);
raf.write(buffer, offset, beforeEof);
raf.seek(HEADER_LENGTH);
raf.write(buffer, offset + beforeEof, count - beforeEof);
}
}
 
/**
  * Reads count bytes into buffer from file. Wraps if necessary.
  *
  * @param position in file to read from
  * @param buffer to read into
  * @param count # of bytes to read
  */
private void ringRead(int position, byte[] buffer, int offset, int count)
throws IOException {
position = wrapPosition(position);
if (position + count <= fileLength) {
raf.seek(position);
raf.readFully(buffer, 0, count);
} else {
// The read overlaps the EOF.
// # of bytes to read before the EOF.
int beforeEof = fileLength - position;
raf.seek(position);
raf.readFully(buffer, offset, beforeEof);
raf.seek(HEADER_LENGTH);
raf.readFully(buffer, offset + beforeEof, count - beforeEof);
}
}
 
/**
  * Adds an element to the end of the queue.
  *
  * @param data to copy bytes from
  */
public void add(byte[] data) throws IOException {
add(data, 0, data.length);
}
 
/**
  * Adds an element to the end of the queue.
  *
  * @param data to copy bytes from
  * @param offset to start from in buffer
  * @param count number of bytes to copy
  *
  * @throws IndexOutOfBoundsException if {@code offset < 0} or
  * {@code count < 0}, or if {@code offset + count} is bigger than the length
  * of {@code buffer}.
  */
public synchronized void add(byte[] data, int offset, int count)
throws IOException {
Objects.nonNull(data, "buffer");
if ((offset | count) < 0 || count > data.length - offset) {
throw new IndexOutOfBoundsException();
}
 
expandIfNecessary(count);
 
// Insert a new element after the current last element.
boolean wasEmpty = isEmpty();
int position = wasEmpty ? HEADER_LENGTH : wrapPosition(
last.position + Element.HEADER_LENGTH + last.length);
Element newLast = new Element(position, count);
 
// Write length.
writeInt(buffer, 0, count);
ringWrite(newLast.position, buffer, 0, Element.HEADER_LENGTH);
 
// Write data.
ringWrite(newLast.position + Element.HEADER_LENGTH, data, offset, count);
 
// Commit the addition. If wasEmpty, first == last.
int firstPosition = wasEmpty ? newLast.position : first.position;
writeHeader(fileLength, elementCount + 1, firstPosition, newLast.position);
last = newLast;
elementCount++;
if (wasEmpty) first = last; // first element
}
 
/**
  * Returns the number of used bytes.
  */
private int usedBytes() {
if (elementCount == 0) return HEADER_LENGTH;
 
if (last.position >= first.position) {
// Contiguous queue.
return (last.position - first.position) // all but last entry
+ Element.HEADER_LENGTH + last.length // last entry
+ HEADER_LENGTH;
} else {
// tail < head. The queue wraps.
return last.position // buffer front + header
+ Element.HEADER_LENGTH + last.length // last entry
+ fileLength - first.position; // buffer end
}
}
 
/**
  * Returns number of unused bytes.
  */
private int remainingBytes() {
return fileLength - usedBytes();
}
 
/**
  * Returns true if this queue contains no entries.
  */
public synchronized boolean isEmpty() {
return elementCount == 0;
}
 
/**
  * If necessary, expands the file to accommodate an additional element of the
  * given length.
  *
  * @param dataLength length of data being added
  */
private void expandIfNecessary(int dataLength) throws IOException {
int elementLength = Element.HEADER_LENGTH + dataLength;
int remainingBytes = remainingBytes();
if (remainingBytes >= elementLength) return;
 
// Expand.
int previousLength = fileLength;
int newLength;
// Double the length until we can fit the new data.
do {
remainingBytes += previousLength;
newLength = previousLength << 1;
previousLength = newLength;
} while (remainingBytes < elementLength);
raf.setLength(newLength);
 
// If the buffer is split, we need to make it contiguous.
if (last.position < first.position) {
FileChannel channel = raf.getChannel();
channel.position(fileLength); // destination position
int count = last.position + Element.HEADER_LENGTH + last.length
- HEADER_LENGTH;
if (channel.transferTo(HEADER_LENGTH, count, channel) != count) {
throw new AssertionError("Copied insufficient number of bytes!");
}
 
// Commit the expansion.
int newLastPosition = fileLength + last.position - HEADER_LENGTH;
writeHeader(newLength, elementCount, first.position, newLastPosition);
last = new Element(newLastPosition, last.length);
} else {
writeHeader(newLength, elementCount, first.position, last.position);
}
fileLength = newLength;
}
 
/**
  * Reads the eldest element. Returns null if the queue is empty.
  */
public synchronized byte[] peek() throws IOException {
if (isEmpty()) return null;
int length = first.length;
byte[] data = new byte[length];
ringRead(first.position + Element.HEADER_LENGTH, data, 0, length);
return data;
}
 
/**
  * Invokes reader with the eldest element, if an element is available.
  */
public synchronized void peek(ElementReader reader) throws IOException {
if (elementCount > 0) {
reader.read(new ElementInputStream(first), first.length);
}
}
 
/**
  * Invokes the given reader once for each element in the queue, from
  * eldest to most recently added.
  */
public synchronized void forEach(ElementReader reader) throws IOException {
int position = first.position;
for (int i = 0; i < elementCount; i++) {
Element current = readElement(position);
reader.read(new ElementInputStream(current), current.length);
position = wrapPosition(current.position + Element.HEADER_LENGTH
+ current.length);
}
}
 
/**
  * Reads a single element.
  */
private class ElementInputStream extends InputStream {
private int position;
private int remaining;
private ElementInputStream(Element element) {
position = wrapPosition(element.position + Element.HEADER_LENGTH);
remaining = element.length;
}
@Override public int read(byte[] buffer, int offset, int length)
throws IOException {
Objects.nonNull(buffer, "buffer");
if ((offset | length) < 0 || length > buffer.length - offset) {
throw new ArrayIndexOutOfBoundsException();
}
if (length > remaining) length = remaining;
ringRead(position, buffer, offset, length);
position = wrapPosition(position + length);
remaining -= length;
return length;
}
@Override public int read() throws IOException {
if (remaining == 0) return -1;
raf.seek(position);
int b = raf.read();
position = wrapPosition(position + 1);
remaining--;
return b;
}
}
 
/**
  * Returns the number of elements in this queue.
  */
public synchronized int size() {
return elementCount;
}
 
/**
  * Removes the eldest element.
  *
  * @throw NoSuchElementException if the queue is empty
  */
public synchronized void remove() throws IOException {
if (isEmpty()) throw new NoSuchElementException();
if (elementCount == 1) {
clear();
} else {
// assert elementCount > 1
int newFirstPosition = wrapPosition(first.position
+ Element.HEADER_LENGTH + first.length);
ringRead(newFirstPosition, buffer, 0, Element.HEADER_LENGTH);
int length = readInt(buffer, 0);
writeHeader(fileLength, elementCount - 1, newFirstPosition, last.position);
elementCount--;
first = new Element(newFirstPosition, length);
}
}
 
/**
  * Clears this queue. Truncates the file to the initial size.
  */
public synchronized void clear() throws IOException {
if (fileLength > INITIAL_LENGTH) raf.setLength(INITIAL_LENGTH);
writeHeader(INITIAL_LENGTH, 0, 0, 0);
elementCount = 0;
first = last = Element.NULL;
fileLength = INITIAL_LENGTH;
}
 
/**
  * Closes the underlying file.
  */
public synchronized void close() throws IOException {
raf.close();
}
 
@Override public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName()).append('[');
builder.append("fileLength=").append(fileLength);
builder.append(", size=").append(elementCount);
builder.append(", first=").append(first);
builder.append(", last=").append(last);
builder.append(", element lengths=[");
try {
forEach(new ElementReader() {
boolean first = true;
public void read(InputStream in, int length) throws IOException {
if (first) {
first = false;
} else {
builder.append(", ");
}
builder.append(length);
}
});
} catch (IOException e) {
Square.warning(e);
}
builder.append("]]");
return builder.toString();
}
 
/** A pointer to an element. */
static class Element {
 
/** Length of element header in bytes. */
static final int HEADER_LENGTH = 4;
 
/** Null element. */
static final Element NULL = new Element(0, 0);
 
/** Position in file. */
final int position;
 
/** The length of the data. */
final int length;
 
/**
  * Constructs a new element.
  *
  * @param position within file
  * @param length of data
  */
Element(int position, int length) {
this.position = position;
this.length = length;
}
 
@Override public String toString() {
return getClass().getSimpleName() + "["
+ "position = " + position
+ ", length = " + length + "]";
}
}
 
/**
  * Reads queue elements. Enables partial reads as opposed to reading all
  * of the bytes into a byte[].
  */
public interface ElementReader {
 
/*
  * TODO: Support remove() call from read().
  */
 
/**
  * Called once per element.
  *
  * @param in stream of element data. Reads as many bytes as requested,
  * unless fewer than the request number of bytes remains, in which case it
  * reads all the remaining bytes.
  * @param length of element data in bytes
  */
public void read(InputStream in, int length) throws IOException;
}
}
 
QueueFileTest.java:
 
package com.squareup.util;
 
import android.test.AndroidTestCase;
import com.squareup.Square;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import junit.framework.ComparisonFailure;
 
/**
 * Tests for QueueFile.
 *
 * @author Bob Lee (bob@squareup.com)
 */
public class QueueFileTest extends AndroidTestCase {
 
/**
  * Takes up 33401 bytes in the queue (N*(N+1)/2+4*N). Picked 254 instead of
  * 255 so that the number of bytes isn't a multiple of 4.
  */
private static int N = 254; //
private static byte[][] values = new byte[N][];
static {
for (int i = 0; i < N; i++) {
byte[] value = new byte[i];
// Example: values[3] = { 3, 2, 1 }
for (int ii = 0; ii < i; ii++) value[ii] = (byte) (i - ii);
values[i] = value;
}
}
 
private File file;
 
@Override protected void setUp() throws Exception {
file = getContext().getFileStreamPath("test.queue");
file.delete();
}
 
@Override protected void tearDown() throws Exception {
file.delete();
}
 
public void testAddOneElement() throws IOException {
// This test ensures that we update 'first' correctly.
QueueFile queue = new QueueFile(file);
byte[] expected = values[253];
queue.add(expected);
assertEquals(expected, queue.peek());
queue.close();
queue = new QueueFile(file);
assertEquals(expected, queue.peek());
}
 
public void testAddAndRemoveElements() throws IOException {
long start = System.nanoTime();
 
Queue<byte[]> expected = new LinkedList<byte[]>();
 
for (int round = 0; round < 5; round++) {
QueueFile queue = new QueueFile(file);
for (int i = 0; i < N; i++) {
queue.add(values[i]);
expected.add(values[i]);
}
 
// Leave N elements in round N, 15 total for 5 rounds. Removing all the
// elements would be like starting with an empty queue.
for (int i = 0; i < N - round - 1; i++) {
assertEquals(expected.remove(), queue.peek());
queue.remove();
}
queue.close();
}
 
// Remove and validate remaining 15 elements.
QueueFile queue = new QueueFile(file);
assertEquals(15, queue.size());
assertEquals(expected.size(), queue.size());
while (!expected.isEmpty()) {
assertEquals(expected.remove(), queue.peek());
queue.remove();
}
queue.close();
 
// length() returns 0, but I checked the size w/ 'ls', and it is correct.
// assertEquals(65536, file.length());
 
Square.debug("Ran in " + ((System.nanoTime() - start) / 1000000) + "ms.");
}
 
/**
  * Tests queue expansion when the data crosses EOF.
  */
public void testSplitExpansion() throws IOException {
// This should result in 3560 bytes.
int max = 80;
 
Queue<byte[]> expected = new LinkedList<byte[]>();
QueueFile queue = new QueueFile(file);
 
for (int i = 0; i < max; i++) {
expected.add(values[i]);
queue.add(values[i]);
}
 
// Remove all but 1.
for (int i = 1; i < max; i++) {
assertEquals(expected.remove(), queue.peek());
queue.remove();
}
 
// This should wrap around before expanding.
for (int i = 0; i < N; i++) {
expected.add(values[i]);
queue.add(values[i]);
}
 
while (!expected.isEmpty()) {
assertEquals(expected.remove(), queue.peek());
queue.remove();
}
 
queue.close();
}
 
public void testFailedAdd() throws IOException {
QueueFile queueFile = new QueueFile(file);
queueFile.add(values[253]);
queueFile.close();
 
final BrokenRandomAccessFile braf = new BrokenRandomAccessFile(file, "rwd");
queueFile = new QueueFile(braf);
 
try {
queueFile.add(values[252]);
fail();
} catch (IOException e) { /* expected */ }
 
braf.rejectCommit = false;
 
// Allow a subsequent add to succeed.
queueFile.add(values[251]);
 
queueFile.close();
 
queueFile = new QueueFile(file);
assertEquals(2, queueFile.size());
assertEquals(values[253], queueFile.peek());
queueFile.remove();
assertEquals(values[251], queueFile.peek());
}
 
public void testFailedRemoval() throws IOException {
QueueFile queueFile = new QueueFile(file);
queueFile.add(values[253]);
queueFile.close();
 
final BrokenRandomAccessFile braf = new BrokenRandomAccessFile(file, "rwd");
queueFile = new QueueFile(braf);
 
try {
queueFile.remove();
fail();
} catch (IOException e) { /* expected */ }
 
queueFile.close();
 
queueFile = new QueueFile(file);
assertEquals(1, queueFile.size());
assertEquals(values[253], queueFile.peek());
 
queueFile.add(values[99]);
queueFile.remove();
assertEquals(values[99], queueFile.peek());
}
 
public void testFailedExpansion() throws IOException {
QueueFile queueFile = new QueueFile(file);
queueFile.add(values[253]);
queueFile.close();
 
final BrokenRandomAccessFile braf = new BrokenRandomAccessFile(file, "rwd");
queueFile = new QueueFile(braf);
 
try {
// This should trigger an expansion which should fail.
queueFile.add(new byte[8000]);
fail();
} catch (IOException e) { /* expected */ }
 
queueFile.close();
 
queueFile = new QueueFile(file);
 
assertEquals(1, queueFile.size());
assertEquals(values[253], queueFile.peek());
assertEquals(4096, queueFile.fileLength);
 
queueFile.add(values[99]);
queueFile.remove();
assertEquals(values[99], queueFile.peek());
}
 
public void testPeakWithElementReader() throws IOException {
QueueFile queueFile = new QueueFile(file);
final byte[] a = { 1, 2 };
queueFile.add(a);
final byte[] b = { 3, 4, 5 };
queueFile.add(b);
 
queueFile.peek(new QueueFile.ElementReader() {
public void read(InputStream in, int length) throws IOException {
assertEquals(length, 2);
byte[] actual = new byte[length];
in.read(actual);
assertEquals(a, actual);
}
});
 
queueFile.peek(new QueueFile.ElementReader() {
public void read(InputStream in, int length) throws IOException {
assertEquals(length, 2);
assertEquals(1, in.read());
assertEquals(2, in.read());
assertEquals(-1, in.read());
}
});
 
queueFile.remove();
 
queueFile.peek(new QueueFile.ElementReader() {
public void read(InputStream in, int length) throws IOException {
assertEquals(length, 3);
byte[] actual = new byte[length];
in.read(actual);
assertEquals(b, actual);
}
});
 
assertEquals(b, queueFile.peek());
assertEquals(1, queueFile.size());
}
 
public void testForEach() throws IOException {
QueueFile queueFile = new QueueFile(file);
 
final byte[] a = { 1, 2 };
queueFile.add(a);
final byte[] b = { 3, 4, 5 };
queueFile.add(b);
 
final int[] iteration = new int[] { 0 };
QueueFile.ElementReader elementReader = new QueueFile.ElementReader() {
public void read(InputStream in, int length) throws IOException {
if (iteration[0] == 0) {
assertEquals(length, 2);
byte[] actual = new byte[length];
in.read(actual);
assertEquals(a, actual);
} else if (iteration[0] == 1) {
assertEquals(length, 3);
byte[] actual = new byte[length];
in.read(actual);
assertEquals(b, actual);
} else {
fail();
}
iteration[0]++;
}
};
 
queueFile.forEach(elementReader);
 
assertEquals(a, queueFile.peek());
assertEquals(2, iteration[0]);
}
 
/**
  * Compares two byte[]s for equality.
  */
private static void assertEquals(byte[] expected, byte[] actual) {
if (!Arrays.equals(expected, actual)) {
throw new ComparisonFailure(null, Arrays.toString(expected),
Arrays.toString(actual));
}
}
 
/**
  * A RandomAccessFile that can break when you go to write the COMMITTED
  * status.
  */
static class BrokenRandomAccessFile extends RandomAccessFile {
boolean rejectCommit = true;
BrokenRandomAccessFile(File file, String mode)
throws FileNotFoundException {
super(file, mode);
}
@Override public void write(byte[] buffer) throws IOException {
if (rejectCommit && getFilePointer() == 0) {
throw new IOException("No commit for you!");
}
super.write(buffer);
}
}
}
 


    
[3] 元件之间图标拖拽
    来源: 互联网  发布时间: 2014-02-18
部件之间图标拖拽

又到周末了,尝试实现一个图标拖拽的小程序;主要实现的功能有:

1.两个部件的图标拖动转移

2.可以切换图标查看模式,有大图标和小图标模式两种

3.可以删除图标,添加也应该不难,所以就没实现。

4.可以框选多个图标

5.改变部件大小可以自动重新布局图标

这里初始化左边有十几个图标,右边的部件是空的。

主窗口
class MainWindow:public QMainWindow
{
	Q_OBJECT
public:
	MainWindow(QWidget *parent = NULL);
	~MainWindow();

private:
	Splitter    *m_pSplitter;
	MainWidget   *m_pLeftWidget;
	MainWidget   *m_pRightWidget;
	QScrollArea  *m_pSplitterArea;
};

MainWindow::MainWindow( QWidget *parent /*= NULL*/ ):QMainWindow(parent)
{
	this->setWindowTitle("IconDemo");
	m_pSplitter = new Splitter(this);
	m_pLeftWidget = new MainWidget(this);
	m_pLeftWidget->init();
	m_pRightWidget = new MainWidget(this);

	QSize size = m_pRightWidget->size();
	m_pSplitterArea = new QScrollArea(this);
	m_pSplitterArea->setWidget(m_pSplitter);
	m_pSplitter->addWidget(m_pLeftWidget);
	m_pSplitter->addWidget(m_pRightWidget);
	m_pSplitter->setMinimumSize(QSize(700,700));
	m_pSplitterArea->setMinimumSize(QSize(700,600));

	m_pSplitter->setCollapsible(0,false);
	m_pSplitter->setCollapsible(1,false);

	this->setStyleSheet(" QFrame{background-image: url(/blog_article/_/DragIcon/Resources/51.jpg) }");

	this->setFixedSize(QSize(700,550));
	connect(m_pLeftWidget,SIGNAL(heightChangeSignal(int)),m_pSplitter,SLOT(heightChangeSlot(int  )));
	connect(m_pRightWidget,SIGNAL(heightChangeSignal(int)),m_pSplitter,SLOT(heightChangeSlot(int )));

}

MainWindow::~MainWindow()
{

}

分割器
自定义分割器主要是为了在调节的时候可以改变其高度
class Splitter:public QSplitter
{
	Q_OBJECT
public:
	Splitter(QWidget *parent = NULL);
	~Splitter();
protected slots:
	void heightChangeSlot(int height);
private:
};

Splitter::Splitter( QWidget *parent /*= NULL*/ ):QSplitter(parent)
{

}

Splitter::~Splitter()
{

}

void Splitter::heightChangeSlot( int height )
{
	this->setMinimumHeight(height);
}

控制器和数据结构
Controller主要用于控制数据结构,添加和删除图标等。这里还自定义了一个ItemMimeData用于拖拽图标
enum {BigIcon_Mode = 0, SmallIcon_Mode};
struct IconItemData
{
	QImage  image;
	QString name;
	int mode ;
	IconItemData()
	{
		mode = SmallIcon_Mode;
	}
};

class Controller:public QObject
{
	Q_OBJECT
public:
	Controller(QObject *parent = NULL);
	~Controller();
	void init();
	void addItem(IconItemData* pItem);
	void deleteItem(int index);
	void deleteItem(IconItemData* pItem);
	void changeIconMode(int mode);
	size_t getSize()
	{
		return m_IconDataVec.size();
	}

	IconItemData* getItem(int index);

protected:
	
private:
	vector<IconItemData*>  m_IconDataVec;
};


class ItemMimeData:public QMimeData
{
	Q_OBJECT
public:
	ItemMimeData():QMimeData()
	{
		m_pDragItemList = NULL;
	}

	~ItemMimeData()
	{
		if (m_pDragItemList)
		{
			delete m_pDragItemList;
		}
	}

	void SetDragDatas(QString mimeType , QList<IconItemData*> *pItemList)
	{
		m_format<<mimeType;
		m_pDragItemList = pItemList;
	}

	QStringList formats() const
	{
		return m_format;
	}

	const QList<IconItemData*>* DragItemData() const
	{
		return m_pDragItemList;
	}



protected:

	QVariant retrieveData(const QString &mimetype, QVariant::Type preferredType) const
	{
		if (mimetype == "ItemMimeData")
		{
			return m_pDragItemList;
		}

		else
		{
			 return QMimeData::retrieveData(mimetype, preferredType);  
		}
	}
private:
	QStringList              m_format;
	const QList<IconItemData*> *m_pDragItemList;
};

void Controller::addItem( IconItemData* pItem )
{
	if (pItem)
	{
		m_IconDataVec.push_back(pItem);
	}
}

void Controller::deleteItem( int index )
{
	if ((index > 0) && (index < m_IconDataVec.size()))
	{
		vector<IconItemData*>::iterator it = m_IconDataVec.begin();
		it = it + index;
		m_IconDataVec.erase(it);
	}
}

void Controller::deleteItem( IconItemData* pItem )
{
	if (pItem)
	{
		vector<IconItemData*>::iterator it = m_IconDataVec.begin();
		for (it; it != m_IconDataVec.end(); ++it)
		{
			if (pItem == *it)
			{
				m_IconDataVec.erase(it);
				break;
			}
		}
	}
}

IconItemData* Controller::getItem( int index )
{
	if ((index >= 0) && (index < m_IconDataVec.size()))
	{
		return m_IconDataVec[index];
	}
}

void Controller::init()
{
	for (int i = 0; i < 20; ++i)
	{
		IconItemData *pItem = new IconItemData;
		pItem->name = QString::number(i);
		QString iconPath = QString(":/DragIcon/Resources/%1.jpg").arg(i);
		QFile Iconfile(iconPath);
		if (Iconfile.exists())
		{
			pItem->image = QImage(iconPath);
			m_IconDataVec.push_back(pItem);
		}
		else
		{
			delete pItem;
		}
	}
}

Controller::Controller( QObject *parent /*= NULL*/ ):QObject(parent)
{
	//init();
}

Controller::~Controller()
{

}

void Controller::changeIconMode( int mode )
{
	for (int i = 0; i < m_IconDataVec.size(); ++i)
	{
		m_IconDataVec[i]->mode = mode;
	}
}

图标部件
IconItemWidget主要由一个label显示图标,lineEdit来显示名称
class ItemNameLineEdit:public QLineEdit
{
	Q_OBJECT
public:
	ItemNameLineEdit(QWidget *parent = NULL);
	~ItemNameLineEdit();
protected:
	void mouseDoubleClickEvent ( QMouseEvent * event );
	private slots:
		void finishEditSlot();
};

class IconItemWidget:public QWidget
{
	Q_OBJECT
public:
	IconItemWidget(IconItemData *pData,QWidget *parent = NULL);
	~IconItemWidget();

	void unSelectedItem()
	{
		m_selected = false;
	}
	void SelectItem()
	{
		m_selected = true;
	}

	IconItemData *getData()
	{
		return m_pItemData;
	}
protected:
	void resizeEvent ( QResizeEvent * event ) ;
	void paintEvent ( QPaintEvent * event ) ;
private:
	QLabel              *m_pImage;
	ItemNameLineEdit    *m_pNameLEdit;
	IconItemData        *m_pItemData;
	bool                 m_selected;
	QPoint               m_mousePressPos;
};

IconItemWidget::IconItemWidget( IconItemData *pData,QWidget *parent /*= NULL*/ ):QWidget(parent),m_pItemData(pData)
{
	m_selected = false;
	m_pImage = new QLabel(this);
	m_pNameLEdit = new ItemNameLineEdit(this);
	m_pNameLEdit->setAlignment(Qt::AlignCenter);
	QSize imageSize;
	QPixmap pixmap ;
	if (m_pItemData->mode == BigIcon_Mode)
	{
		pixmap = QPixmap::fromImage(m_pItemData->image).scaled(QSize(100,100),Qt::KeepAspectRatio);
		 imageSize = pixmap.size();
		
		m_pImage->setPixmap(pixmap);
		m_pNameLEdit->setText(m_pItemData->name);
		const int spacing = 5;
		int nameheight = 15;
		m_pImage->setGeometry(spacing,spacing,imageSize.width(),imageSize.height());
		m_pNameLEdit->setGeometry(spacing,spacing + imageSize.height(),imageSize.width(),nameheight);
		this->setFixedSize(QSize(imageSize.width() + 10,imageSize.height() + 25));
	} 
	else if (m_pItemData->mode == SmallIcon_Mode)
	{
		pixmap = QPixmap::fromImage(m_pItemData->image).scaled(QSize(80,80),Qt::KeepAspectRatio);
		 imageSize = pixmap.size();
		m_pImage->setPixmap(pixmap);
		m_pNameLEdit->setText(m_pItemData->name);
		const int spacing = 5;
		int nameheight = 15;
		m_pImage->setGeometry(spacing,spacing,imageSize.width(),imageSize.height());
		m_pNameLEdit->setGeometry(spacing,spacing + imageSize.height(),imageSize.width(),nameheight);
		this->setFixedSize(QSize(imageSize.width() + 10,imageSize.height() + 25));
	}
	
	
}

IconItemWidget::~IconItemWidget()
{

}

void IconItemWidget::resizeEvent( QResizeEvent * event )
{
	QWidget::resizeEvent(event);
}

void IconItemWidget::paintEvent( QPaintEvent * event )
{
	if (m_selected)
	{
		//添加选中样式边框
		this->setStyleSheet("QLabel{border-width: 2px;border-style: solid;border-color: blue;}");
	}
	else
	{
		//取消选中样式
		this->setStyleSheet("");
	}
	QWidget::paintEvent(event);
}

void ItemNameLineEdit::mouseDoubleClickEvent( QMouseEvent * event )
{
	this->setReadOnly(false);
}

ItemNameLineEdit::ItemNameLineEdit( QWidget *parent /*= NULL*/ ):QLineEdit(parent)
{
	this->setContextMenuPolicy(Qt::NoContextMenu);   //禁用默认右键菜单
	this->setReadOnly(true);
	connect(this ,SIGNAL(editingFinished ()),this,SLOT(finishEditSlot()));
}

ItemNameLineEdit::~ItemNameLineEdit()
{

}

void ItemNameLineEdit::finishEditSlot()
{
	this->setReadOnly(true);
}

布局部件
class MainWidget:public QWidget
{
	Q_OBJECT
public:
	MainWidget(QWidget *parent = NULL);
	~MainWidget();
	
	void init();

private slots:
	void bigModeSlot();
	void smallModeSlot();
	void reLayoutIconSlot();
	void deleteItemSlot();

protected:
	void mousePressEvent ( QMouseEvent * event );
	void mouseMoveEvent ( QMouseEvent * event );
	void mouseReleaseEvent(QMouseEvent *event);
	void dragEnterEvent ( QDragEnterEvent * event );
	void dragLeaveEvent ( QDragLeaveEvent * event );
	void dragMoveEvent ( QDragMoveEvent * event ) ;
	void dropEvent(QDropEvent *event);

	void resizeEvent ( QResizeEvent * event );
	void paintEvent ( QPaintEvent * event );
	QRect GetItemRect( int index);
	void clear();
	void performDrag();
	void SelectItem();
	bool HitTest(QMouseEvent * event);
	bool isInVector(IconItemWidget* pItem);
signals:
	void heightChangeSignal(int height);
private:
	int                         iconMode;
	Controller                 *m_pController;
	vector<IconItemWidget*>     m_ItemVec;
	QPushButton             *m_pAddButton;
	QPoint               m_mousePressPos;
	vector<IconItemWidget*>  m_selectItemVec;
	QPoint               m_mousePos;                
};

MainWidget::MainWidget( QWidget *parent /*= NULL*/ ):QWidget(parent),iconMode(SmallIcon_Mode)
{
	this->setAcceptDrops(true);
	m_pController = new Controller(this);
	//init();
	this->setMinimumWidth(100);
}

MainWidget::~MainWidget()
{

}

void MainWidget::init()
{
	m_pController->init();
	for (int i = 0; i < m_pController->getSize(); ++i)
	{
		IconItemWidget *pItemWidget = new IconItemWidget(m_pController->getItem(i),this);
		m_ItemVec.push_back(pItemWidget);
	}
}
//获取每个图标应该布局的位置
 QRect MainWidget::GetItemRect( int index )
{
	if (index < 0 || index > m_ItemVec.size())
	{
		return QRect();
	}
	const int spacing = 5;
	int width = this->width();
	int height = this->height();

	int itemWidth = m_ItemVec[index]->width();
	int itemHeight = m_ItemVec[index]->height();
	int colCount = width / (itemWidth + spacing );
	int rowCount = height / (itemHeight + spacing);
	int row = index / colCount;
	int col = index % colCount;
	int xPos = col * (itemWidth + spacing );
	int yPos = row * (itemHeight + spacing);
	return QRect(xPos,yPos,itemWidth,itemHeight);
}

 void MainWidget::resizeEvent( QResizeEvent * event )
 {
	 //改变大小了要重新布局
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 if (i == m_ItemVec.size() - 1)
		 {
			 this->setMinimumHeight(rect.y() + 20);
			 emit heightChangeSignal(this->height());
		 }
		
		 m_ItemVec[i]->setGeometry(rect);
	 }
	 QWidget::resizeEvent(event);
 }

 void MainWidget::paintEvent( QPaintEvent * event )
 {
	 if (m_mousePos.x() == 0 && m_mousePos.y() == 0)
	 {
		 return;
	 }
	 //画红色选框
	 QRect rect(m_mousePressPos,m_mousePos);
	 QPainter painter(this);
	 painter.setPen(Qt::red);
	 painter.drawRect(rect);
	 update();
	 QWidget::paintEvent(event);
 }

 void MainWidget::mousePressEvent( QMouseEvent * event )
 {
	 m_mousePressPos = event->pos();
	 //点击空白处则情况选中,
	 //如果m_selectItemVec大小为1,则也要清空下面再另外选中
	 //右键单击也要清空m_selectItemVec
	 if (!HitTest(event) || (m_selectItemVec.size() == 1) ||Qt::RightButton == event->button())   
	 {
		for (int i = 0; i < m_selectItemVec.size(); ++i)
		{
			m_selectItemVec[i]->unSelectedItem();
		}
		m_selectItemVec.clear();
	}
	
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 if (rect.contains(event->pos()) && (!isInVector(m_ItemVec[i])))  //图标尚未被选中则添加到m_selectItemVec
		 {
			 m_selectItemVec.push_back(m_ItemVec[i]);
			 m_ItemVec[i]->SelectItem();
		 }
	 }

	 QWidget *pWidget = QApplication::focusWidget();   //如果正在编辑名称,点击别的地方可以结束编辑
	 if (pWidget)
	 {
		 pWidget->clearFocus();
	 }

	 //右键菜单
	 if (Qt::RightButton == event->button())
	 {
		 QMenu *pMenu = new QMenu(this);
		 QAction *pBigModeAct = new QAction(tr("大图标"),pMenu);
		 QAction *pSmallModeAct = new QAction(tr("小图标"),pMenu);
		 QAction *pDeleteAct = new QAction(tr("删除"),pMenu);
		  if (m_selectItemVec.size() > 0)   //有选中的则弹出删除菜单
		  {
			   pMenu->addAction(pDeleteAct);
			  connect(pDeleteAct,SIGNAL(triggered()),this,SLOT(deleteItemSlot()));
		  }
		  else
		  {
			  //点击空白处则可切换图标模式
			  pMenu->addAction(pBigModeAct);
			  pMenu->addAction(pSmallModeAct);
			  connect(pBigModeAct,SIGNAL(triggered()),this,SLOT(bigModeSlot()));
			  connect(pSmallModeAct,SIGNAL(triggered()),this,SLOT(smallModeSlot()));
		  }
		 
		 pMenu->exec(event->globalPos());
		 delete pMenu;
	 }
	 QWidget::mousePressEvent(event);
 }

 //大图标模式
 void MainWidget::bigModeSlot()
 {
	 m_pController->changeIconMode(BigIcon_Mode);
	 reLayoutIconSlot();
	  this->update();
 }
 //小图标模式
 void MainWidget::smallModeSlot()
 {
	  m_pController->changeIconMode(SmallIcon_Mode);
	   reLayoutIconSlot();
	   this->update();
 }

 void MainWidget::reLayoutIconSlot()
 {
	 clear();    //先清除
	 for (int i = 0; i < m_pController->getSize(); ++i)
	 {
		 //重新生成图标
		 IconItemWidget *pItemWidget = new IconItemWidget(m_pController->getItem(i),this);
		 m_ItemVec.push_back(pItemWidget);
	 }
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 m_ItemVec[i]->setGeometry(rect);
		 m_ItemVec[i]->show();             //重新生成,布局图标必须show才能显示
	 }
	 this->repaint();
 }

 void MainWidget::clear()
 {
	 qDeleteAll(m_ItemVec);
	 m_ItemVec.clear();
 }

 void MainWidget::mouseMoveEvent( QMouseEvent * event )
 {
	 if (event->buttons() & Qt::LeftButton && (m_selectItemVec.size() > 0))
	 {
		 if (( m_mousePressPos - event->pos()).manhattanLength() > QApplication::startDragDistance())
		 {
			 performDrag();
		 }
	 }
	 else
	 {
		 m_mousePos = event->pos();
	 }
	 QWidget::mouseMoveEvent(event);
 }

 void MainWidget::mouseReleaseEvent( QMouseEvent *event )
 {
	 if (m_mousePos.x() == 0 && m_mousePos.y() == 0)
	 {
		 return;
	 }
	 else 
	 {
		 //release鼠标再进行选择
		 SelectItem();
	 }
	 m_mousePos = QPoint();
	 QWidget::mouseReleaseEvent(event);
 }

 void MainWidget::dragEnterEvent( QDragEnterEvent * event )
 {
	 const ItemMimeData *pMimeData = (const ItemMimeData*)event->mimeData();
	 const QList<IconItemData*>* plist = pMimeData->DragItemData();
	 if (plist)
	 {
		 event->accept();
	 }
 }

 void MainWidget::dragLeaveEvent( QDragLeaveEvent * event )
 {

 }

 void MainWidget::dragMoveEvent( QDragMoveEvent * event )
 {
	 event->accept();
 }

 void MainWidget::performDrag()
 {
	 QDrag  *pDrag = new QDrag(this);
	 ItemMimeData *pData = new ItemMimeData;
	  QList<IconItemData*> *plist = new QList<IconItemData*>;
	 for (int i = 0; i < m_selectItemVec.size(); ++i)
	 {
		 plist->append(m_selectItemVec[i]->getData());
	 }
	 pData->SetDragDatas("ItemMimeData",plist);
	 pDrag->setMimeData(pData);

	 QPixmap pixmap = QPixmap::fromImage(m_selectItemVec[0]->getData()->image).scaled(50,50,Qt::KeepAspectRatio);
	 pDrag->setPixmap(pixmap);
	 pDrag->exec(Qt::CopyAction);
	 //delete m_selectItemVec[0];
 }

 void MainWidget::dropEvent( QDropEvent *event )
 {
	 const ItemMimeData *pMimeData = (const ItemMimeData*)event->mimeData();
	 const QList<IconItemData*>* plist = pMimeData->DragItemData();
	 if (plist)
	 {
		 for (int i = 0; i < plist->size(); ++i)
		 {
			 m_pController->addItem(plist->at(i));
		 }
		 reLayoutIconSlot();
		 event->accept();
	 }

 }

 void MainWidget::deleteItemSlot()
 {
	 //删除再重新布局
	 for (int i = 0; i < m_selectItemVec.size(); ++i)
	 {
		 m_pController->deleteItem(m_selectItemVec[i]->getData());
	 }
	 reLayoutIconSlot();
 }


 //框选多个图标
 void MainWidget::SelectItem()
 {
	  QRect rect(m_mousePressPos,m_mousePos);
	  for (int i = 0; i < m_ItemVec.size(); ++i)
	  {
		  QPoint centerPos = GetItemRect(i).center();
		  if (rect.contains(centerPos))
		  {
			  m_ItemVec[i]->SelectItem();
			  m_selectItemVec.push_back(m_ItemVec[i]);
		  }
	  }
 }

 //有点击图标则返回true,否则返回false
 bool MainWidget::HitTest( QMouseEvent * event )
 {
	 for (int i = 0; i < m_ItemVec.size(); ++i)
	 {
		 QRect rect = GetItemRect(i);
		 if (rect.contains(event->pos()))
		 {
			return true;
		 }
	 }
	 return false;
 }
 //检查图标是否已经被选中
 bool MainWidget::isInVector(IconItemWidget* pItem )
 {
	 for (int i = 0; i < m_selectItemVec.size(); ++i)
	 {
		 if (m_selectItemVec[i] == pItem)
		 {
			 return true;
		 }
	 }
	 return false;
 }

结果截图;



    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3